2020 China Collegiate Programming Contest Weihai Site补题部分

A. Golden Spirit

签到题,首先把所有老人带到对岸,然后在对休息讨论一下即可。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int main()
{
    IO;
    int T=1;
    cin>>T;
    while(T--)
    {
        ll n,x,t;
        cin>>n>>x>>t;
        ll p=2*n*t;
        if(p-2*t>=x) cout<<2*p<<'\n';
        else
        {
            ll w=x-p+2*t;
            if(w>=t) 
            {
                p+=t;
                cout<<2*n*t+p+max(0ll,x-2*n*t)<<'\n';
            }
            else
                cout<<2*p+w<<'\n';
        }
    }
    return 0;
}

C. Rencontre

大佬题解

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=200010;
int n,m;
int h[N],e[2*N],ne[2*N],idx;
ll w[2*N];
int sz[N];
int can[N][4];
int cnt[4];
void add(int a,int b,ll c)
{
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
ll res1,res2,res3;
void dfs(int u,int fa)
{
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j==fa) continue;
        dfs(j,u);
        for(int k=1;k<=3;k++) can[u][k]+=can[j][k];
        res1+=w[i]*can[j][1]*(cnt[2]-can[j][2])+w[i]*can[j][2]*(cnt[1]-can[j][1]);
        res2+=w[i]*can[j][2]*(cnt[3]-can[j][3])+w[i]*can[j][3]*(cnt[2]-can[j][2]);
        res3+=w[i]*can[j][3]*(cnt[1]-can[j][1])+w[i]*can[j][1]*(cnt[3]-can[j][3]);
    }
}

int main()
{
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
        memset(h,-1,sizeof h);
        cin>>n;
        for(int i=1;i<n;i++)
        {
            int a,b;
            ll c;
            cin>>a>>b>>c;
            add(a,b,c),add(b,a,c);
        }
        for(int i=1;i<=3;i++)
        {
            cin>>cnt[i];
            for(int j=1;j<=cnt[i];j++)
            {
                int x;
                cin>>x;
                can[x][i]=1;
            }
        }
        dfs(1,-1);
        double d1=(double)res1/((double)cnt[1]*cnt[2]);
        double d2=(double)res2/((double)cnt[3]*cnt[2]);
        double d3=(double)res3/((double)cnt[1]*cnt[3]);
        double ans=(d1+d2+d3)/2;
        printf("%.9lf\n",ans);
    }
   
    return 0;
}

自己非常害怕树的问题,尤其是树形dp之类的
总结:像这种考虑贡献的可以尝试逐点考虑或者逐边考虑(本题)

D. ABC Conjecture

c = p 1 α 1 p 2 α 2 … p k α k c=p_1^{\alpha_1}p_2^{\alpha_2}\dots p_k^{\alpha_k} c=p1α1p2α2pkαk
只要存在 α i > 1 \alpha_i>1 αi>1就能够满足题意,如下尝试构造一组 a b ab ab,不妨设 α i > 1 \alpha_i>1 αi>1
a = p 1 α 1 … ( p i α i − 1 ) … p 1 α 1 a=p_1^{\alpha_1}\dots (p_i^{\alpha_i-1})\dots p_1^{\alpha_1} a=p1α1(piαi1)p1α1
b = p 1 α 1 … [ ( p i − 1 ) × p i α i − 1 ] … p 1 α 1 b=p_1^{\alpha_1}\dots [(p_i-1)×p_i^{\alpha_i-1}]\dots p_1^{\alpha_1} b=p1α1[(pi1)×piαi1]p1α1
明显上述 a + b = c a+b=c a+b=c,且由于 p i − 1 < p i p_i-1<p_i pi1<pi脑补一下 r a d ( a b c ) < c rad(abc)<c rad(abc)<c一定成立

由于c范围很大,如果你只会线性筛只需要先线性筛质数,然后试除法分解质因数,但是可能分解不彻底,对于分解之后剩下的部分只需要特判一下(由于 ( 1 0 7 ) 3 > 1 0 18 (10^7)^3>10^{18} (107)3>1018),如果存在大于 1 0 7 10^7 107的质因数,该质因数的次幂最大是2。由此可特判

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=10000010;
int cnt,prime[N];
bool st[N];
void init(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) prime[++cnt]=i;
        for(int j=1;prime[j]<=n/i;j++)
        {
            st[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    IO;
    int T=1;
    cin>>T;
    init(10000000);
    while(T--)
    {
        ll c;
        cin>>c;
        bool ok=0;
        for(int i=1;i<=cnt;i++)
        {
            ll p=prime[i];
            int s=0;
            if(c%p==0)
            {
                while(c%p==0)
                    c/=p,s++;
            }
            if(s>=2) ok=1;
        }
        ll x=sqrt(c);
        if(c>1&&1ll*x*x==c) ok=1;
        if(ok) cout<<"yes\n";
        else cout<<"no\n";
    }
    return 0;
}

如果没想到上述特判方法那么需要更快速的方法分解质因数,Pollard’s rho模板题?我想可能出题人本意不是这个,会的越多就能越暴力解决问题,降低思维难度!!!

总结:做题还是需要多想想,而且要相信对于自己现在的掌握的算法已经足够解决一些题目。

G. Caesar Cipher

线段树+hash
看到这个题想到hash了,不过由于hash需要取模而且题目中也需要取模自己就非常乱,根本不明白什么时候取哪个模😵

看到正解后发现非常巧妙,由于每次只进行+1,而且对于65536取模,最终可以知道q次询问后溢出数的总个数不会很多,由此每次进行区间+1后我们check一下是否有溢出的数,如果有直接单点修改即可,只需要多维护一个区间最大值mx。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=500010,P=131;
const int mod1=1e9+7;
const int mod2=65536;
struct node
{
    int l,r;
    ll lazy;
    ll hs,mx;
}tree[N<<2];
ll p[N],one[N];
int n,q;
void pushup(int u)
{
    int len=tree[u<<1|1].r-tree[u<<1|1].l+1;
    tree[u].hs=(tree[u<<1].hs*p[len]%mod1+tree[u<<1|1].hs)%mod1;
    tree[u].mx=max(tree[u<<1].mx,tree[u<<1|1].mx);
}
void build(int u,int l,int r)
{
    tree[u]={l,r,0};
    if(l==r)
    {
        cin>>tree[u].hs;
        tree[u].mx=tree[u].hs;
        return;
    }
    int mid=l+r>>1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}
void pushdown(int u)
{
    if(tree[u].lazy==0) return;
    
    int lenl=tree[u<<1].r-tree[u<<1].l+1;
    int lenr=tree[u<<1|1].r-tree[u<<1|1].l+1;
    
    tree[u<<1].hs=(tree[u<<1].hs+tree[u].lazy*one[lenl]%mod1)%mod1;
    tree[u<<1|1].hs=(tree[u<<1|1].hs+tree[u].lazy*one[lenr]%mod1)%mod1;
    
    tree[u<<1].mx+=tree[u].lazy;
    tree[u<<1|1].mx+=tree[u].lazy;
    
    tree[u<<1].lazy+=tree[u].lazy;
    tree[u<<1|1].lazy+=tree[u].lazy;
    tree[u].lazy=0;
}
void add(int u,int l,int r)
{
    if(l<=tree[u].l&&tree[u].r<=r)
    {
        tree[u].lazy++;
        tree[u].mx++;
        
        int len=tree[u].r-tree[u].l+1;
        tree[u].hs=(tree[u].hs+one[len])%mod1;
        return;
    }
    pushdown(u);
    int mid=tree[u].l+tree[u].r>>1;
    if(l<=mid) add(u<<1,l,r);
    if(r>mid) add(u<<1|1,l,r);
    pushup(u);
}
ll query(int u,int l,int r)
{
    if(l<=tree[u].l&&tree[u].r<=r) return tree[u].hs;
    pushdown(u);
    int mid=tree[u].r+tree[u].l>>1;
    ll v=0;
    if(r<=mid) v=query(u<<1,l,r);
    else if(l>mid) v=query(u<<1|1,l,r);
    else
        v=(query(u<<1,l,mid)*p[r-mid]%mod1+query(u<<1|1,mid+1,r))%mod1;
    return v;
}
void check(int u)
{
    if(tree[u].mx<mod2) return;
    if(tree[u].l==tree[u].r) 
    {
        tree[u].mx-=mod2;
        tree[u].hs-=mod2;
        return;
    }
    pushdown(u);
    if(tree[u<<1].mx>=mod2) check(u<<1);
    if(tree[u<<1|1].mx>=mod2) check(u<<1|1);
    pushup(u);
}
int main()
{
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
        cin>>n>>q;
        p[0]=1;
        for(int i=1;i<=n;i++) 
            p[i]=p[i-1]*P%mod1,one[i]=(one[i-1]*P%mod1+1)%mod1;

        build(1,1,n);
        
        while(q--)
        {
            int op,l,r;
            cin>>op>>l>>r;
            if(op==1) 
            {
                add(1,l,r);
                check(1);
            }
            else
            {
                int len;
                cin>>len;
                if(query(1,l,l+len-1)==query(1,r,r+len-1)) cout<<"yes\n";
                else cout<<"no\n";
            }
        }
    }
    return 0;
}

H. Message Bomb

大佬题解
c n t i cnt_i cnti当前群消息个数, a n s i ans_i ansi i i i个人收到消息个数,用一个set记录当前某人所在的群聊。
差分的思想:一个人加入群聊时减去该群聊之前的消息数,退出群聊时加上该群聊当前的消息数,最后加上未退出的群聊消息数

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=200010;
int n,m,s;
int cnt[N];
int ans[N];
set<int> g[N];
int main()
{
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
        cin>>n>>m>>s;
        while(s--)
        {
            int op,x,y;
            cin>>op>>x>>y;
            if(op==1)
            {
                g[x].insert(y);
                ans[x]-=cnt[y];
            }
            else if(op==2)
            {
                g[x].erase(y);
                ans[x]+=cnt[y];
            }
            else
            {
                cnt[y]++;
                ans[x]--;
            }
        }
        for(int i=1;i<=m;i++) 
        {
            for(auto t:g[i])
                ans[i]+=cnt[t];
            cout<<ans[i]<<'\n';
        }
    }
    return 0;
}

L. Clock Master

筛素数+分组背包
#include<cmath>中的log()用不得!!!

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=30010;
double f[N];
int prime[N],cnt;
bool st[N];
double lg[N];
void init(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) prime[++cnt]=i;
        for(int j=1;prime[j]<=n/i;j++)
        {
            st[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    IO;
    int T=1;
    cin>>T;
    init(30000);
    for(int i=1;i<=30000;i++) lg[i]=log(i);
    for(int i=1;i<=cnt;i++)
    {
        for(int j=30000;j>=0;j--)
        {
            ll v=1;
            for(int k=1;;k++)
            {
                v=v*prime[i];
                if(v>j) break;
                f[j]=max(f[j],f[j-v]+k*lg[prime[i]]);
            }
        }
    }
    while(T--)
    {
        int b;
        cin>>b;
        printf("%.7lf\n",f[b]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值