zoukankan      html  css  js  c++  java
  • 21.06.06 训练赛

    B Reverse Game

    题意

    ​ 一个博弈游戏,开始给定一个长度为n的01字符串,每次操作可以选择如下形式中的子串:10,110,100,1010。选定后将其翻转,即为一次操作。双方轮流操作,某方不能操作即失败。Alice先手,对于给定的字符串,谁胜?(1 leqslant n leqslant 10^6)

    题解

    签到。
    首先显然,最终局面一定是如00000...11111...的形式。如果我们把相邻两个数交换记为一次操作,那么题意所说的操作可以分解为一或两次操作,如10变为01为1次操作,100变为001为2两次操作。设(sum)={变成最终局面需要执行的操作次数},那么每次操作要么让(sum-1),要么让(sum-2)。同时我们可以发现,在(sum geqslant 3)的时候,先手如果让(sum-1),后手必然能够让(sum-2)。反之亦然。这就是经典博弈问题之一了。(Ans=(sum:mod:3==0?Bob: Alice))

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=1e6;
    char S[maxn+8];
     
    int main()
    {
    	  scanf("%s",S+1);
    	  int tmp=0,cnt=0,len=strlen(S+1);
    	  for (int i=1;i<=len;i++)
    		    {
    			      if (S[i]=='1') tmp++;
    			      else cnt=(cnt+tmp)%3;
    		    }
    	  cnt?puts("Alice"):puts("Bob");
    	  return 0;
    }
    

    E Divisible by 3

    题意

    给你一个序列([a_i]),问有多少子序列([l,r])满足(weight_{l,r}=sum_{l leqslant ileqslant jleqslant r}a_i imes a_j equiv 0pmod3)。序列长在([1,5 imes 10^5])范围内。

    题解

    签到。

    定义(f_{i,j,k})为有多少个以i为结尾的子序列,满足(weight=j mod 3),且序列和为(k)那么转移就很简单了。具体看代码。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int maxn=5e5;
    int n;
    ll f[maxn+8][3][3];
    int a[maxn+8];
    
    int read()
    {
    	  int x=0,f=1;char ch=getchar();
    	  for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
    	  for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	  return x*f;
    }
    
    int main()
    {
    	  n=read();
    	  for (int i=1;i<=n;i++) a[i]=read()%3;
    	  for (int i=1;i<=n;i++)
    		    {
    			      for (int j=0;j<3;j++)
    						for (int k=0;k<3;k++)
    						  f[i][(j+k*a[i])%3][(k+a[i])%3]+=f[i-1][j][k];
    			      f[i][0][a[i]]++;
    		    }
    	  ll ans=0;
    	  for (int i=1;i<=n;i++) for (int j=0;j<3;j++) ans+=f[i][0][j];
    	  printf("%lld
    ",ans);
    	  return 0;
    }
    

    M Mistake

    题意

    给定n个点m条边的有向无环图,给一个n*k的序列,保证每个(1 leqslant i leqslant n)都在序列中出现k次。将这个序列划分为k个序列(划分后序列中的数相对顺序不变),满足每个序列都是这张有向无环图的合法拓扑序。保证存在合法构造。(1 leqslant nkleqslant 5 imes 10^5)

    题解

    看起来很难实际很sb的一题。

    首先为了满足拓扑序,其实就是对于序列给出了一些诸如x必须在y之前出现的限制。那么我们考虑这样构造:对于某一个位置上的数x,它属于的编组序号就是数x到这个位置出现的次数。我们利用反证法证明正确性:如果存在两个数x,y和他们第i次出现的位置(pos_{x,i}、pos_{y,i}),如果x必须出现在y之前而(pos_{x,i}>pos_{y,i}),那么可知将(pos_{x,i})也不能和(pos_{y,i})之前的y放在同一编组,同时如果跟(pos_{y,i})之后的某一个(pos_{y,j})放在同一编组,那么(pos_{y,i})又会和(pos_{x,j})冲突(因为(i<j),由构造方法可知(pos_{x,j} > pos_{x,i} > pos_{y,i}))。所以存在合法的构造当且仅当这种构造方法合法。

    代码实现就简单了(所以和图有什么关系)。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=5e5;
    int id[maxn+8];
    int n,k,m;
    
    int read()
    {
    	  int x=0,f=1;char ch=getchar();
    	  for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
    	  for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	  return x*f;
    }
    
    int main()
    {
    	  n=read(),k=read(),m=read();
    	  for (int i=1;i<=m;i++) {read(),read();}
    	  for (int i=1;i<=n*k;i++)
    		    {
    			      int x=read();
    			      printf("%d ",++id[x]);
    		    }
    	  return 0;
    }
    
  • 相关阅读:
    清除浮动
    echarts设置小图标位置
    dedecms 顶级栏目内容显示
    dedecms 后台网站 标题设置
    mouseover,mouseenter,mouseout,mouseleave的区别
    texterea 水平居中
    echarts x轴文字换行显示
    echarts 拐点添加图片
    css首行缩进2个字符
    bootstrap 内边框样式
  • 原文地址:https://www.cnblogs.com/Alseo_Roplyer/p/14882522.html
Copyright © 2011-2022 走看看