zoukankan      html  css  js  c++  java
  • Atcoder Yahoo Programming Contest 2019 简要题解

    A-C

    直接放代码吧。

    A

    int n,k;
    int main()
    {
      n=read();k=read();
      puts(k<=(n+1)/2?"YES":"NO");
      return 0;
    }
    

    B

    int d[N];pair<int,int>s[10];
    int main()
    {
      for(int i=1,u,v;i<=3;i++){
        u=read();v=read();
        s[i].first=u;s[i].second=v;
        d[u]++;d[v]++;
      }
      sort(s+1,s+3+1);
      for(int i=2;i<=3;i++)if(s[i]==s[i-1])return puts("NO"),0;
      for(int i=1;i<=4;i++)if(d[i]>=3)return puts("NO"),0;
      return puts("YES"),0;
    }
    

    C

    int main()
    {
      int k=read(),a=read(),b=read();ll ans=0;
      if(b<=a+2||k<=a-1)printf("%d
    ",k+1);
      else{
        k-=a-1;ans=a;if(k&1)k--,ans++;
        printf("%lld
    ",ans+1ll*(k/2)*(b-a));
      }
      return 0;
    }
    

    D - Ears

    zsy在一条([0,L])的数轴上来回走路。
    zsy可以任选([0,L])中的整点作为起点和终点,并且zsy走路时只能在整数位置((0,1,2,...,L))调整方向。
    每当zsy向左或向右经过一条([i,i+1] (iin[0,L)))的线段时,zsy就会往这条线段的中间放上一个球。
    当zsy走完路后,yyb会来到这条数轴。她会进行若干次操作:打爆一个球或在一条线段的中间放上一个球。
    现在给出数轴每条线段中间最终球的个数(a_1,...,a_n),求出zsy的一种行走方式,使得yyb的操作次数最小。

    因为zsy可以反复横跳来回地走,所以可以把(a_i)减去若干个2,最后只剩下(0,1,2)三种状态。
    可以知道对应简化数组的一种最优方案里zsy不会重复走过一条路超过2次。
    既然是回路问题,考虑插头dp。
    (f[i][j][k])表示考虑轮廓线到达(i),插头有(j)个,已经用了(k)个单插头的最少代价,
    直接转移即可。

    int n,t[N];ll suft[N],dp[N][3][3],ans;
    inline void upd(ll &a,ll b){a=a<b?a:b;}
    inline int calc(int x,int r){
      if(r==0)return x;
      if(r==1)return x&1?0:1;
      if(r==2){if(!x)return 2;else return x&1?1:0;}
    }
    int main()
    {
      n=read();for(int i=1;i<=n;i++)t[i]=read();
      for(int i=n;i;i--)suft[i]=suft[i+1]+t[i];ans=suft[1];
      memset(dp,63,sizeof(dp));dp[0][0][0]=0;
      for(int i=0;i<=n;i++)
        for(int a=0;a<3;a++)
          for(int b=0;b<3;b++){
        	if(a==0){
        	  upd(dp[i+1][a][b],dp[i][a][b]+t[i+1]);
        	  if(b!=2)upd(dp[i+1][a+1][b+1],dp[i][a][b]+calc(t[i+1],1));
        	  upd(dp[i+1][a+2][b],dp[i][a][b]+calc(t[i+1],2));
        	}
        	if(a==1){
        	  if(b!=2)upd(ans,dp[i][a][b]+suft[i+1]);
        	  upd(dp[i+1][a][b],dp[i][a][b]+calc(t[i+1],1));
        	  if(b!=2)upd(dp[i+1][a+1][b+1],dp[i][a][b]+calc(t[i+1],2));
        	}
        	if(a==2){
        	  upd(ans,dp[i][a][b]+suft[i+1]);
        	  if(b!=2)upd(dp[i+1][a-1][b+1],dp[i][a][b]+calc(t[i+1],1));
        	  upd(dp[i+1][a][b],dp[i][a][b]+calc(t[i+1],2));
        	}
          }
      printf("%lld
    ",ans);
      return 0;
    }
    

    E - Odd Subrectangles

    考虑给定行后选出列集合的方案数:
    如果行的异或和不为0,那么总有一半的方案选出来异或和为1,另一半为0,因此方案为(2^{m-1})
    于是答案变成(2^{m-1}S),其中(S)表示行向量选出来的异或和不为(0)的方案数。
    求解选取行向量集合,使其异或和不为0的方案数是一个经典问题:
    考虑求出(n)个行向量的线性基,设其大小为(r)
    如果仅选取线性基中的元素,显然无法使得异或和为(0);
    那么考虑先选取不在线性基中的元素:
    对于这样的一组方案,在线性基中都有唯一的一种选取元素的方案,使得所有元素的异或和为0.
    因此(S=2^n-2^{n-r})

    int n,m,a[N][N],now[N],in[N],p[N][N],r;
    inline int poww(int a,int b){
      int res=1;
      for(;b;b>>=1,a=1ll*a*a%mod)
        if(b&1)res=1ll*res*a%mod;
      return res;
    }
    int main()
    {
      n=read();m=read();
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)a[i][j]=read();
      for(int i=1;i<=n;i++){
        memcpy(now,a[i],sizeof(now));
        for(int j=1;j<=m;j++)
          if(now[j]){
    	if(in[j])for(int k=j;k<=m;k++)now[k]^=p[j][k];
    	else{in[j]=1;memcpy(p[j],now,sizeof(p[j]));r++;break;}
          }
      }
      printf("%lld
    ",1ll*(poww(2,n)-poww(2,n-r)+mod)%mod*poww(2,m-1)%mod);
      return 0;
    }
    

    F - Pass

    考虑直接构造最终序列。由传球方式可以知道,第(i(ile n))个球只会在(1-i)个人的手中出现,后(n)个求随意。
    因此直接设(f[i][j])dp,最后组合数乘一下即可。

    char s[N];int n,dp[N][N],c[N][N],ans;
    inline void upd(int &a,int b){a+=b;if(a>=mod)a-=mod;}
    int main()
    {
      scanf("%s",s+1);n=strlen(s+1);
      for(int i=0;i<=n;i++)
        for(int j=c[i][0]=1;j<=i;j++)upd(c[i][j]=c[i-1][j],c[i-1][j-1]);
      dp[0][0]=1;
      for(int i=1;i<=n;i++)
        for(int j=0,c=s[i]-48;j<=i;j++){
          if(j>=c-1)upd(dp[i][j],dp[i-1][j-c+1]);
          if(j>=c)upd(dp[i][j],dp[i-1][j-c]);
        }
      for(int i=0;i<=n;i++)upd(ans,1ll*dp[n][i]*c[n][i]%mod);
      printf("%d
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    css水平垂直居中问题
    关系型数据库四大特性
    C++读取csv文件&&收获到的知识
    恒生面试记录
    SQL数据库操作命令
    安防产品知识记录
    学会求助(带着自己的理解去和别人探讨解决方案),处理问题责任清晰,如果不清楚可以问主管.
    一个简单又不简单的socket例子
    C++面试题总结
    大华电话面试
  • 原文地址:https://www.cnblogs.com/cjfdf/p/10358465.html
Copyright © 2011-2022 走看看