Educational Codeforces Round 74 (Rated for Div. 2)
我叼,打的时候CF被ddos了,还有这种操作?害得我只能睡觉
最后一题留坑
A. Prime Subtraction
以为是求GCD,上去wa一发。。。后来发现,y-x=C,如果C不为1,那么肯定可以由素数组成,偶数直接+2,奇数就是3+2*k ,k>=0
#include<bits/stdc++.h> #define LL long long #define pii pair<int,int> #define pb push_back #define mp make_pair using namespace std; int main(){ int t; LL a,b; scanf("%d",&t); while(t--){ scanf("%lld%lld",&a,&b); if (a-b==1){ printf("NO\n"); }else { printf("YES\n"); } } return 0; }
B 先打远的,每次打完,判断一下是否有被震到x<0的,直接模拟即可
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> using namespace std; const int maxx = 2e5+6; int a[maxx]; vector<int>v; bool cmp(int x,int y){ return x<y; } int main(){ int q; int n; long long rr; scanf("%d",&q); while(q--){ v.clear(); scanf("%d%lld",&n,&rr); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); v.push_back(a[i]); } sort(v.begin(),v.end(),cmp); v.erase(unique(v.begin(),v.end()),v.end()); int l=0,r=v.size()-1; long long step=0; int ans=0; while(l<=r){ ans++; r--; step+=rr; while(l<=r && v[l]-step<=0){ l++; } } printf("%d\n",ans); } return 0; }
C. Standard Free2play
我们发现只要两个数间隔差>=2比如5-3,你一定可以先到4;100-1你一定可以先到2,然后我们判断如果当前和下一个是连续的,也就是说3-2,那么你可以先到4,然后3的状态改变,然后到2,否则就不行,我们
就必须用一个魔法值,前面说了a[i+1]-a[i]>1那么你可以直接改变当前i的状态,然后走到a[i+1]+1的状态。最后判断一下,最后的状态是不是高度大于2,如果是的话,我们直接改变最后的状态,然后就可以到0了。
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> using namespace std; const int maxx = 2e5+6; int a[maxx]; int main(){ int t; int h,n; scanf("%d",&t); while(t--){ scanf("%d%d",&h,&n); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); } int cnt=0; for (int i=1;i<=n;i++){ if (a[i]>=h){ continue; } if (h-a[i]>1){ h=a[i]+1; } if (i<n){ if (a[i+1]==a[i]-1){ h=a[i+1]; }else{ cnt++; h=a[i]; } continue; } if (h>2)cnt++; } printf("%d\n",cnt); } return 0; }
D 找出所有的串,每一个字符都至少属于一个回文串,发现其实这种回文串很多,我们反着考虑,找不满足的,那么只有ABBBBB,BAAAAAA,AAAAB,BBBBBA这四种类型,其他的都是,因为字符毕竟只有两种,
那么前后扫一遍即可,
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> #define LL long long using namespace std; const int maxx= 3e5+6; char a[maxx]; int main(){ LL n; while(~scanf("%lld",&n)){ scanf("%s",&a); int len=strlen(a); LL ans=n*(n-1)/2; int pre=0; for (int i=1;i<len;i++){ if (a[i]==a[i-1])continue; ans++; ans-=(i-pre); pre=i; } pre=len-1; for (int i=len-2;i>=0;i--){ if (a[i]==a[i+1])continue; ans-=(pre-i); pre=i; } printf("%lld\n",ans); } return 0; }
E 很有意思,我们暂时也不怎么懂,这个DP太秀了。。。我们发现位数只有20位,那么其实可以通过枚举已经安排的状态来考虑。
当前状态i代表当前i的二进制位上的英文单词是否被安排
参考一下
https://www.cnblogs.com/codedecision/p/11647681.html
#include <bits/stdc++.h> #define LL long long using namespace std; const int maxx = 1e5+6; const int maxn = 2e6+7; char str[maxx]; LL dp[maxn]; LL cnt[30][30]; int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ scanf("%s",str); int len=strlen(str); for (int i=1;i<len;i++){ int x=str[i-1]-'a'; int y=str[i]-'a'; if (x!=y)cnt[x][y]++,cnt[y][x]++; } for (int i=1;i<=(1<<m);i++){ dp[i]=INT_MAX; } for (int i=0;i<(1<<m)-1;i++){ LL c=__builtin_popcount(i); for (int j=0;j<m;j++){ if(!(i&(1<<j))){ LL tmp=dp[i]; for (int k=0;k<m;k++){ if (i&(1<<k)){ tmp+=cnt[j][k]*c; }else { tmp-=cnt[j][k]*c; } } dp[i|(1<<j)]=min(dp[i|(1<<j)],tmp); } } } printf("%lld\n",dp[(1<<m)-1]); } return 0; }
F 树上毛毛虫
其实就是找一条链,与这个链直接相连的节点尽可能的多。
其实树形DP,就可以,我们维护两个大的DP值,代表儿子节点中最大的两个值,dp[i],代表i的子树中链上所连接的点尽可能的多。
那么对于每个节点,维护一个maxx,minn,代表不同的儿子节点中,子树链上连接的点,最多的和次多的,然后维护一个maxx+minn+son[i]-2+1表示把两个链连在一起,加上当前节点的儿子节点的个数,减去由于maxx和minn链上两个点是在son里面,再加上当前节点本身。
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> #define LL long long using namespace std; const int maxx = 3e5+6; int ver[maxx*2],Next[maxx*2],head[maxx]; int n,m,tot; int dp[maxx],son[maxx]; int ans; void add(int x,int y){ ver[++tot]=y;Next[tot]=head[x];head[x]=tot; ver[++tot]=x;Next[tot]=head[y];head[y]=tot; son[x]++; son[y]++; } void dfs(int u,int fa){ dp[u]=1; int minn=0,maxx=1; for (int i=head[u];i;i=Next[i]){ int v=ver[i]; if (v==fa)continue; dfs(v,u); if (maxx<dp[v]){ minn=maxx; maxx=dp[v]; }else if (minn<dp[v]){ minn=dp[v]; } dp[u]=max(dp[u],dp[v]+son[u]-1); } ans=max(minn+maxx+son[u]-1,ans); } int main(){ int uu,vv; int t; scanf("%d",&t); while(t--){ scanf("%d",&n); ans=0; for (int i=1;i<=n;i++){ dp[i]=0; head[i]=0; son[i]=0; } for (int i=1;i<=n-1;i++){ scanf("%d%d",&uu,&vv); add(uu,vv); } dfs(1,0); printf("%d\n",ans); } return 0; }