ICPC 2024 江西 vp

A. Maliang Learning Painting

a+b+c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <bits/stdc++.h>
#define mk(x,y) make_pair(x,y)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
typedef long long ll;
const int N=5e5+7,mod=1e9+7;


void solve()
{
    ll a,b,c;
    cin>>a>>b>>c;
    printf("%lld\n",a+b+c);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T=1;
    // cin>>T;
    while(T--) {
        solve();
    }
    return 0;
}

C. Liar

如果总和不等于 S,让其中一人承担代价即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <bits/stdc++.h>
#define mk(x,y) make_pair(x,y)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)>(y)?(y):(x))
#define int long long
using namespace std;
typedef long long ll;
const int N=5e5+7,mod=1e9+7;


void solve()
{
    
   int n,s;
   cin>>n>>s;
   int sum=0;
   for(int i=1;i<=n;i++)
   {
        int x;
        cin>>x;
        sum+=x;
   }
   if(sum==s) cout<<n;
   else
   {
        cout<<n-1;
   }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T=1;
    //cin>>T;
    while(T--) {
        solve();
    }
    return 0;
}

G. Multiples of 5

判断是不是 5 的倍数,只看最后一位是不是 5 || 0 就行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <bits/stdc++.h>
#define mk(x,y) make_pair(x,y)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
typedef long long ll;
const int N=5e5+7,mod=1e9+7;


void solve()
{
    
    ll n,ans=0;
    cin>>n;
    for(ll i=1;i<=n;++i) {
        ll x,y;
        char c;
        cin>>x>>c;
        if(c=='A')  y=10;
        else  y=c-'0';
        ans+=x*y;
        ans%=10;
    }
    if(ans==0||ans==5)  printf("Yes\n");
    else  printf("No\n");
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T=1;
    cin>>T;
    while(T--) {
        solve();
    }
    return 0;
}

K. Magic Tree

简单手模推断为 $2^{m-1}$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <bits/stdc++.h>
#define mk(x,y) make_pair(x,y)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
typedef long long ll;
#define int long long
const int N=1e6+7,mod=998244353;


void solve()
{
    ll ans=1;
    ll m;
    cin>>m;
    for(int i=1;i<m;++i)  ans=ans*2%mod;
    printf("%lld",ans);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T=1;
    // cin>>T;
    while(T--) {
        solve();
    }
    return 0;
}

J. Magic Mahjong

两种胡牌:

  • 十三张特定的,其中一张出现了两次。
  • 七对牌。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <bits/stdc++.h>
#define mk(x,y) make_pair(x,y)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
typedef long long ll;
#define int long long
const int N=1e6+7,mod=998244353;

string a[20]={"1z", "2z", "3z", "4z", "5z", "6z", "7z", "1p", "9p", "1s", "9s", "1m", "9m"};

void solve()
{
    string s;
    getline(cin,s);
    map<string,int>vis;
    int cnt=0;
    for(int i=0;i<28;i+=2){
        string tmp=s.substr(i,2);
        if(vis[tmp]==0)cnt++;
        vis[tmp]++;
    }
    if(cnt==7){
        for(auto [x,y]:vis){
            if(y!=2){
                cout<<"Otherwise\n";
                return;
            }
        }
        cout<<"7 Pairs\n";
    }
    else if(cnt==13){
        for(int i=0;i<13;i++){
            if(vis[a[i]]==0){
                cout<<"Otherwise\n";
                return;
            }
        }
        cout<<"Thirteen Orphans\n";
    }
    else cout<<"Otherwise\n";
}
signed main()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    int T=1;
    cin>>T;
    cin.ignore();
    while(T--) {
        solve();
    }
    return 0;
}

L. Campus

对每个门跑 dijkstra, 同时注意到特殊时间点至多只有 30 个,对这些时间点分别检查统计答案。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#include <bits/stdc++.h>
#define mk(x,y) make_pair(x,y)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
typedef long long ll;
#define int long long
const int N=1e5+7,mod=998244353,inf=1e9+7;
struct node{
    int tim,id,op;
}b[32];
int n,m,k,t;
int vis[N],p[N],l[N],r[N];
ll ans[N],a[N],mi[N],dis[16][N];
bool open[N];
vector<pair<int,int>>e[N];

void dijkstra(int x)
{
    for(int i=1;i<=n;i++)dis[x][i]=1e9,vis[i]=0;
    multiset<pair<ll,int>>s;
    dis[x][p[x]]=0;
    s.insert({dis[x][p[x]],p[x]});
    while(!s.empty()){
        ll now=s.begin()->second,tmp=s.begin()->first;
        s.erase(s.begin());
        if(vis[now])  continue;
        vis[now]=1;
        for(auto [xx,yy]:e[now]){
            if(vis[xx])continue;
            if(dis[x][xx]>dis[x][now]+yy) {
                dis[x][xx]=dis[x][now]+yy;
                s.insert({dis[x][xx],xx});
            }
            
        }
    }
}
bool cmp(node x,node y){return x.tim<y.tim;}
void sol(int tim)
{
    for(int i=1;i<=n;i++)  mi[i]=inf;
    bool flag=0;
    for(int i=1;i<=k;i++) {
        if(!open[i])  continue;
        flag=1;
        for(int j=1;j<=n;j++)  mi[j]=min(mi[j],dis[i][j]);
    }
    if(!flag) {ans[tim]=-1;return;}
    ll sum=0;
    for(int i=1;i<=n;i++)  sum+=a[i]*mi[i];
    ans[tim]=sum;
}
void solve()
{
    ans[0]=-1;
    int tot=0;
    cin>>n>>m>>k>>t;
    for(int i=1;i<=t;i++){
        ans[i]=-2;
    }
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=k;i++){
        cin>>p[i]>>l[i]>>r[i];
        b[++tot]=node{l[i],i,1};
        b[++tot]=node{r[i]+1,i,0};
    }
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        e[u].push_back({v,w});
        e[v].push_back({u,w});
    }
    for(int i=1;i<=k;i++){
        dijkstra(i);
    }
    sort(b+1,b+1+tot,cmp);
    for(int i=1;i<=tot;i++){
        open[b[i].id]=b[i].op;
        if(i==tot||b[i].tim!=b[i+1].tim)  sol(b[i].tim);
    }
    for(int i=1;i<=t;i++){
        if(ans[i]==-2)  ans[i]=ans[i-1];
        printf("%lld\n",ans[i]);
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T=1;
    // cin>>T;
    while(T--) {
        solve();
    }
    return 0;
}

H. Convolution

看着哈人,实际为二维前缀和之后,找最大值即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7, mod=1e9+7;

void solve(){
    int n,m,k,l;
    cin>>n>>m>>k>>l;
    vector<vector<int>>I(n+1,vector<int>(m+1));
    vector<vector<int>>S(n+1,vector<int>(m+1));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>I[i][j];
            S[i][j]=S[i-1][j]+S[i][j-1]-S[i-1][j-1]+I[i][j];
        }
    }
    int ans=0;
    for(int i=1;i+n-k<=n;++i)
        for(int j=1;j+m-l<=m;++j) {
            int tmp=S[i+n-k][j+m-l]-S[i+n-k][j-1]-S[i-1][j+m-l]+S[i-1][j-1];
            ans+=abs(tmp);
        }
    cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t=1;
    // cin>>t;
    while(t--)solve();
    return 0;
}

D. Magic LCM

对于两个数 \( x < y \),若它们存在公因子 \( k \),那么有:

$$[ \frac{x}{k} + y \cdot k > y \cdot (k - 1) + y > x + y ]$$

操作一定优。

所以对每个数的质因子分别操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <bits/stdc++.h>
using namespace std;
#define ls now<<1
#define rs now<<1|1
#define endl "\n"
#define lowbit(x) ((x)&(-x))
typedef long long ll;
const int N=1e3+7, mod=998244353;

vector<ll>pm,num[N*N];
map<int,int>vis;

void init(){
    for(int i=2;i<=N;i++){
        if(!vis[i])pm.push_back(i);
        for(int j=2;j*i<=N;j++){
            vis[j*i]=1;
        }
    }
}

bool cmp(int x,int y){return num[x].size()>num[y].size();}

void solve(){
    int n;
    cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    vector<int>b;
    for(int i=1;i<=n;i++){
        ll tmp=a[i];
        for(auto j:pm){
            ll t=1;
            while(tmp%j==0){
                t*=j;
                tmp/=j;
            }
            if(t!=1){
                if(num[j].empty())b.push_back(j);
                num[j].push_back(t);
            }
        }
        if(tmp!=1){
            if(num[tmp].empty())b.push_back(tmp);
            num[tmp].push_back(tmp);
        }
    }
    sort(b.begin(),b.end(),cmp);
    for(auto i:b)sort(num[i].begin(),num[i].end());
    ll ans=0,cnt=0;
    while(!b.empty()){
        ll tmp=1;
        for(auto i:b){
            tmp=tmp*num[i].back()%mod;
            num[i].pop_back();
        }
        ++cnt;
        ans=ans+tmp%mod;
        while(!b.empty()&&num[b.back()].empty())b.pop_back();
    }
    ans=(ans+n-cnt)%mod;
    cout<<ans<<endl;
    for (auto p : b) num[p].clear();
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    init();
    int t=1;
    cin>>t;
    while(t--)solve();
    return 0;
}

B. Magic Leeks

初始值和增长值应该分开考虑。

如果转头,只会转一次。

如果 $t>=2*n$ 一定能走完所有的格子。

枚举转头的位置即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>
using namespace std;
#define ls now << 1
#define rs now << 1 | 1
#define endl "\n"
#define lowbit(x) ((x) & (-x))
typedef long long ll;
const int N = 2e5 + 7, mod = 1e9 + 7;

ll calc(int x, int r) {  // 计算 (r-m+1)+(r-m+2)+...+r
    return x * (2ll * r - x + 1) / 2;
}

void solve() {
    int n, p;
    cin >> n >> p;
    vector<int> v(n + 10);
    vector<ll> pre(n + 10);
    for (int i = 1; i <= n; i++) {
        cin >> v[i];
        pre[i] = pre[i - 1] + v[i];
    }
    int k, t;
    cin >> k >> t;
    ll ans = 0;
    if (t >= 2 * n) {
        ans = pre[n] + k * calc(n, t);
    } else {
        for (int r = p; r <= n; ++r) {
            ll dr = r - p;
            ll dl = min<ll>(p - 1, t - 2 * dr - 1);
            if (dl < 0) break;
            int L = p - dl;
            ll len = dl + dr + 1;
            ll seg = pre[r] - pre[L - 1];
            ans = max(ans, seg + k * calc(len, t));
        }

        for (int l = p; l >= 1; --l) {
            ll dl = p - l;
            ll dr = min<ll>(n - p, t - 2 * dl - 1);
            if (dr < 0) break;
            int R = p + dr;
            ll len = dl + dr + 1;
            ll seg = pre[R] - pre[l - 1];
            ans = max(ans, seg + k * calc(len, t));
        }
    }
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

I. Neuvillette Circling

依旧放弃计算几何./

实际上,所有的最小覆盖圆都由这 $n$ 个点中的 两点(当它们作为直径端点时)或 三点 唯一确定。 因此,只需枚举

  • 两点确定的圆,共 $n^2$ 个;
  • 三点确定的圆,共 $n^3$ 个。

对于每个枚举出的圆,再计算它能覆盖多少点以及它的半径。由此即可维护所有覆盖恰好 $k$ 个点的圆中最小的半径

整体时间复杂度为 $O(n^4)$。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <bits/stdc++.h>
using namespace std;
using ld = long double;
const ld INF = 1e100;
const ld EPS = 1e-9;

struct P { ld x, y; };

static inline ld sqr(ld x) { return x * x; }
static inline ld dist2(const P& a, const P& b) {
    return sqr(a.x - b.x) + sqr(a.y - b.y);
}

/* 末项 t, 长度 m 的等差数列和 (用来把圆半径推进到更小的 s) */
static inline int need_s(int m) {
    // 最小 s 使 C(s,2) >= m
    int s = 1;
    while (1LL * s * (s - 1) / 2 < m) ++s;
    return s;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;                       // 读入点
    if (!(cin >> n)) return 0;
    vector<P> a(n);
    for (auto& p : a) cin >> p.x >> p.y;

    /* f[s] = 覆盖 >= s 个点的圆的最小半径 */
    vector<ld> f(n + 1, INF);
    f[1] = 0.0;                  // 单点半径为 0

    /* -------- 两点构直径圆 -------- */
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            P c{ (a[i].x + a[j].x) / 2.0L, (a[i].y + a[j].y) / 2.0L };
            ld r2 = dist2(a[i], c);          // 半径平方
            int cnt = 0;
            for (auto& p : a)
                if (dist2(p, c) <= r2 + 1e-8) ++cnt;
            f[cnt] = min(f[cnt], (ld)sqrt(r2));
        }
    }

    /* -------- 三点构外接圆 -------- */
    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
            for (int k = j + 1; k < n; ++k) {
                const auto &A = a[i], &B = a[j], &C = a[k];
                ld D = 2 * (A.x * (B.y - C.y) + B.x * (C.y - A.y) + C.x * (A.y - B.y));
                if (fabsl(D) < EPS) continue;          // 共线,不会出现(题目保证)
                ld xNum = (sqr(A.x) + sqr(A.y)) * (B.y - C.y) +
                          (sqr(B.x) + sqr(B.y)) * (C.y - A.y) +
                          (sqr(C.x) + sqr(C.y)) * (A.y - B.y);
                ld yNum = (sqr(A.x) + sqr(A.y)) * (C.x - B.x) +
                          (sqr(B.x) + sqr(B.y)) * (A.x - C.x) +
                          (sqr(C.x) + sqr(C.y)) * (B.x - A.x);
                P center{ xNum / D, yNum / D };
                ld r2 = dist2(center, A);

                int cnt = 0;
                for (auto& p : a)
                    if (dist2(p, center) <= r2 + 1e-8) ++cnt;
                    f[cnt] = min(f[cnt], (ld)sqrt(r2));
            }

    /* -------- 单调化:覆盖 >= s 的最小半径 -------- */
    for (int s = n - 1; s >= 1; --s)
        f[s] = min(f[s], f[s + 1]);

    /* -------- 输出 -------- */
    int M = n * (n - 1) / 2;
    cout.setf(ios::fixed);
    cout << setprecision(10);

    for (int m = 1; m <= M; ++m) {
        int s = need_s(m);
        cout << f[s] << endl;
    }
    return 0;
}
Licensed under CC BY-NC-SA 4.0
最后更新于 Sep 11, 2025 16:27 +0800
发表了95篇文章 · 总计15万2千字
永远相信美好的事情即将发生。
使用 Hugo 构建
主题 StackJimmy 设计