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
");
    }else {
        printf("YES
");
    }
  }
  return 0;
}
View Code

  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
",ans);
   }
   return 0;
}
View Code

  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
",cnt);
  }
  return 0;
}
View Code

  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
",ans);
  }
  return 0;
}
View Code

  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
",dp[(1<<m)-1]);
    }
    return 0;
}
View Code

 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
",ans);
  }
  return 0;
}
View Code
原文地址:https://www.cnblogs.com/bluefly-hrbust/p/11662661.html