Codeforces Round #360 (Div. 1)

本文提供了三道算法竞赛题目的解答思路及代码实现:通过数学性质解决余数游戏问题;使用存在性背包方法优化求解特定数值组合问题;设计并查集算法应对王国划分挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

B. Remainders Game

  如果两个数模所有 ci 结果一样,这两个数的差一定是 LCM(ci) 的整数倍。要使得能够唯一确定一个 xmodk LCM(ci) 必须是 k 的整数倍。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int c[1000010];

bool notP[1000010];
int primes[1000010];
int sz = 0;

int cnt[1000010];

int main(){
    for(int i=2;i<=1000;i++){
        for(int j=i+i;j<=1000000;j+=i){
            notP[j] = 1;
        }
    }
    for(int i=2;i<=1000;i++){
        if(!notP[i]){
            primes[sz++] = i;
        }
    }

    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        scanf("%d",&c[i]);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<sz;j++){
            int cur = 0;
            while(c[i]%primes[j] == 0){
                cur++;
                c[i] /= primes[j];
            }
            cnt[primes[j]] = max(cnt[primes[j]],cur);
        }
        cnt[c[i]] = 1;
    }
    bool ok = 1;
    for(int i=0;i<sz;i++){
        int cur = 0;
        while(k%primes[i] == 0){
            cur++;
            k /= primes[i];
        }
        if(cnt[primes[i]]<cur){
            ok = 0;
        }
    }
    if(cnt[k]<1){
        ok = 0;
    }
    if(ok){
        cout<<"Yes"<<endl;
    }else{
        cout<<"No"<<endl;
    }
    return 0;
}

C. The Values You Can Make

  就是存在性背包,多弄一维,作为C题实在太水了。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int mod = 1e9+7; 

const int maxn = 1000010;

bool dp2[500*500+10][1010];
int c[555];

int ans[500*500+10];

int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>c[i];
    }

    dp2[0][0] = 1;
    for(int i=1;i<=n;i++){
        for(int j=500;j>=0;j--){
            for(int kk=500;kk>=0;kk--){
                if(dp2[j][kk]){
                    if(kk+c[i]<=k)dp2[j][kk+c[i]] = 1;
                    dp2[j+c[i]][kk] = 1;
                }
            }
        }
    }

    int sz=0;
    for(int i=0;i<=k;i++){
        for(int j=0;j<=k;j++){
            if(dp2[i][j] && i+j==k){
                ans[sz++] = i;
            }
        }
    }
    cout<<sz<<endl;
    for(int i=0;i<sz;i++){
        printf("%d ",ans[i]);
    }

    return 0;
}

D. Dividing Kingdom II

  对所有边按从长到短排序,对于每个询问,扫一遍边,利用带关系的并查集,把长的优先分在不同部分,直到不能再分时的边长就是答案。(关系并查集好容易写挫)

#include <bits/stdc++.h>

using namespace std;

#define ll long long

struct Edge{
    int u,v,w;
    int id;
    bool operator<(const Edge& o)const{
        return w>o.w;
    }
}edges[500000];
int n,m,q;

int r[1111];
int p[1111];
bool vis[1111];

void init(){
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++){
        p[i] = i;
        r[i] = 0;
    }
}

pair<int,int> Find(int u){
    if(u==p[u]){
        return make_pair(u,0);
    }

    int v = u;

    while(v!=p[v]){
        v = p[v];
        r[u] ^= r[v];
    } 
    p[u] = v;
    return make_pair(p[u],r[u]);
    pair<int,int> pp = Find(p[u]);
    r[u] = r[p[u]]^r[u];
    p[u] = pp.first;
    return make_pair(p[u],r[u]);
}

void Union(int u,int v,int relation){
    pair<int,int> fu = Find(u);
    pair<int,int> fv = Find(v);
    p[fu.first] = fv.first;

    r[fu.first] = relation^r[u]^r[v];
}

int Relation(int u,int v){
    return r[u]^r[v];
}

int main(){
    cin>>n>>m>>q;
    for(int i=1;i<=m;i++){
        scanf("%d %d %d",&edges[i].u,&edges[i].v,&edges[i].w);
        edges[i].id = i;
    }
    sort(edges+1,edges+m+1);

    for(int i=1;i<=q;i++){
        int ans = -1;
        int l,r;
        scanf("%d %d",&l,&r);
        init();
        for(int j=1;j<=m;j++){
            if(edges[j].id<l || edges[j].id>r){
                continue;
            }
            int u = edges[j].u;
            int v = edges[j].v;

            if(vis[u] && vis[v]){
                if(Find(u).first != Find(v).first){
                    Union(u,v,1);
                }else{
                    if(Relation(u,v) == 0){
                        ans = edges[j].w;
                        break;
                    }
                }
            }else if(vis[u] && !vis[v]){
                Union(v,u,1);
                vis[v] = 1;
            }else if(!vis[u] && vis[v]){
                Union(u,v,1);
                vis[u] = 1;
            }else{
                Union(u,v,1);
                vis[u] = vis[v] = 1;
            }
        }

        printf("%d\n",ans);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值