zoukankan      html  css  js  c++  java
  • [考试反思]1109csp-s模拟测试106:撞词

    (撞哈希了用了模拟测试28的词,所以这次就叫撞词吧)

    蓝色的0。。。

    蓝色的0。。。

    都该联赛了还能CE呢。。。

    考试结束前15分钟左右,期望得分300

    然后对拍发现T2伪了写了一个能拿90分的垃圾随机化

    然后很着急,想再写一个部分分,结果没编译就交了。。。

    不管在多么紧急的情况下,都要检查,编译。

    。。。还不如不对拍拿一个伪的20。。。

    然后T3少考虑一种情况。挂了。

    T1:合并集合merge

    区间dp板子。

     1 #include<cstdio>
     2 #include<bitset>
     3 #include<iostream>
     4 using namespace std;
     5 bitset<303>B[603][603];
     6 int n,x[603],dp[603][603],sz[603][603],ans;
     7 int main(){
     8     freopen("merge.in","r",stdin);freopen("merge.out","w",stdout);
     9     scanf("%d",&n);
    10     for(int i=1;i<=n;++i)scanf("%d",&x[i]),x[i+n]=x[i];
    11     for(int l=1;l<=n<<1;++l){
    12         B[l][l][x[l]]=1;
    13         for(int r=l+1;r<l+n&&r<=n<<1;++r)B[l][r]=B[l][r-1],B[l][r][x[r]]=1;
    14     }
    15     for(int l=1;l<=n<<1;++l)for(int r=l;r<l+n&&r<=n<<1;++r)sz[l][r]=B[l][r].count();
    16     #define r l+len-1
    17     for(int len=2;len<=n;++len)for(int l=1;r<=n<<1;++l)for(int m=l;m<r;++m)
    18         dp[l][r]=max(dp[l][r],dp[l][m]+dp[m+1][r]+sz[l][m]*sz[m+1][r]);
    19     for(int i=1;i<=n;++i)ans=max(ans,dp[i][i+n-1]);
    20     printf("%d
    ",ans);
    21 }
    View Code

    T2:爬climb

    除了最后一步以外,每一步一定用A-B最大的。

    枚举用的最后一个,考虑如何$O(logn)$进行$check$

    发现其实只是i后面的药丸后错了一位,也可以理解为水位在i以后晚了一天才上涨。

    预处理错位前后的两个$sum A-B$与水位的差值,$ST$查询。

    复杂度$O(nlogn)$

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 struct P{
     5     int a,b;
     6     friend bool operator<(P x,P y){
     7         return x.a-x.b>y.a-y.b;
     8     }
     9 }p[100005];
    10 int hb[100005],ans,n,lim;
    11 long long L,sum[100005],h1[100005],h2[100005],wt[100005],st1[18][100005],st2[18][100005];
    12 long long mn1(int l,int r){
    13     if(r<l)return 123456789012345;
    14     int B=hb[r-l+1];
    15     return min(st1[B][l],st1[B][r-(1<<B)+1]);
    16 }
    17 long long mn2(int l,int r){
    18     if(r<l)return 123456789012345;
    19     int B=hb[r-l+1];
    20     return min(st2[B][l],st2[B][r-(1<<B)+1]);
    21 }
    22 int main(){freopen("climb.in","r",stdin);freopen("climb.out","w",stdout);
    23     scanf("%d%lld",&n,&L);ans=lim=n+1;//printf("n=")
    24     for(int i=1;i<=n;++i)scanf("%d%d",&p[i].a,&p[i].b);
    25     sort(p+1,p+1+n);
    26     for(int i=1;i<=n;++i)scanf("%lld",&wt[i]),wt[i]+=wt[i-1];
    27     for(int i=1;i<=n;++i)sum[i]=sum[i-1]+p[i].a-p[i].b;//,printf("%lld
    ",sum[i]);
    28     for(int i=1;i<=n;++i)if(sum[i]<sum[i-1]){lim=i;break;}
    29     for(int i=1;i<=n;++i)h1[i]=h2[i]=sum[i];
    30     for(int i=1;i<=n;++i)h1[i]-=wt[i],h2[i]-=wt[i-1];
    31     for(int i=1;i<=n;++i)st1[0][i]=h1[i],st2[0][i]=h2[i];
    32     for(int j=1;j<18;++j)for(int i=1;i+(1<<j)-1<=n;++i)st1[j][i]=min(st1[j-1][i],st1[j-1][i+(1<<j-1)]);
    33     for(int j=1;j<18;++j)for(int i=1;i+(1<<j)-1<=n;++i)st2[j][i]=min(st2[j-1][i],st2[j-1][i+(1<<j-1)]);
    34     for(int i=0;i<=18;++i)for(int j=1<<i;j<1<<i+1&&j<=n;++j)hb[j]=i;
    35     for(int i=1;i<=n;++i){//printf("%d/%d:%d %d
    ",i,n,p[i].a,p[i].b);
    36         int out1=lower_bound(sum,sum+lim,L-p[i].a)-sum,out2=lower_bound(sum,sum+lim,L-p[i].b)-sum;//printf("%d %d %d
    ",out1,out2,lim);
    37         if(out1==lim&&out2==lim)continue;
    38         if(out1<i&&out1!=lim){//printf("%lld
    ",mn1(1,out));
    39             if(mn1(1,out1)<=0)continue;
    40             ans=min(ans,out1+1);//printf("1:%d %d
    ",i,out1);
    41         }else if(out2>=i&&out2!=lim){//printf("%lld %lld
    ",mn1(1,i-1),mn2(i+1,out));
    42             if(mn1(1,i-1)<=0)continue;
    43             if(mn2(i+1,out2)<=p[i].a-p[i].b)continue;
    44             ans=min(ans,out2);//printf("2:%d %d
    ",i,out2);
    45         }
    46     }printf("%d
    ",ans==n+1?-1:ans);//printf("%lld %lld
    ",mn1(1,5),mn2(7,8));
    47 }
    View Code

    T3:硬币coin

    简单的博弈论。主要不在博弈论,而在转化为图论。

    类似2-SAT的思想(但其实并没什么关系),把每一个行列都拆成2个点,分别表示选与不选。

    连边表示如果存在状态A,那么状态B一定存在。

    根据每一个硬币,如果它是正面,那么如果选这一行那么就必须选这一列,如果不选这一行就不能选这一列。

    双向边$A_1 - B_1$与$A_0 - B_0$。

    如果硬币是反面,那么就是$A_1 - B_0$与$A_0 - B_1$

    连边之后图会成为若干个联通块,互不干扰。

    现在的问题就是确定每一个联通块的状态。

    如果一个联通块内部矛盾(既要选又要不选)那么答案直接根据奇偶判断01。

    否则,如果一个联通块内不管怎么确定状态,需要选的行列都是偶数(简称偶偶),那么对答案没有影响。

    如果存在奇偶块,那么拿到最后一个奇偶块的是必胜的(你可以通过这一块决定全局的步数是奇数还是偶数)

    如果没有奇偶块,那么如果奇奇块的数量是奇数,那么先手必胜3。否则2。

    接下来就考虑如何争夺奇偶块。因为拿到最后一个奇偶块就赢了,所以两个人都不希望拿到倒数第二个奇偶块,那么就想拿到倒数第三个。

    同理推下去,如果奇偶块一共有奇数个,那么先手者一定能拿到最后一个奇偶块,输出3。

    否则,奇偶块一共有偶数个,那么先手者会尽量避免拿到第一个奇偶块。

    所以为了不拿第一个奇偶块,他会去拿奇奇块。(拿偶偶块没有影响)

    拿完奇奇块之后就轮到对手了,对手也同理不想拿奇偶,所以他也会拿奇奇。

    所以两个人现在开始抢奇奇块了。

    如果奇奇块有奇数个,那么先手者就能强制后手者拿走第一个奇偶块,就可以取胜,3。否则就是2。

    所有情况讨论完毕。

     1 #include<cstdio>
     2 int fir[405],l[200005],to[200005],ec=1,pc=1,ord[2][102],ok=1,al[405],sz,cnt,blcnt,sz2,g,sg;
     3 char s[103][103];
     4 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
     5 void Link(int a,int b){link(a,b);link(b,a);}
     6 void dfs(int p){
     7     al[p]=1;sz++;sz2+=p&1;
     8     for(int i=fir[p];i;i=l[i])if(al[to[i]]==0)dfs(to[i]);
     9 }
    10 int main(){
    11     freopen("coin.in","r",stdin);freopen("coin.out","w",stdout);
    12     int t,n,m;
    13     scanf("%d",&t);
    14     while(t--){
    15         scanf("%d%d",&n,&m);
    16         for(int i=1;i<=n;++i)scanf("%s",s[i]+1);
    17         for(int i=1;i<=n;++i)pc+=2,ord[0][i]=pc;
    18         for(int i=1;i<=m;++i)pc+=2,ord[1][i]=pc;
    19         for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
    20             if(s[i][j]=='o')Link(ord[0][i],ord[1][j]),Link(ord[0][i]^1,ord[1][j]^1);
    21             else if(s[i][j]=='x')Link(ord[0][i],ord[1][j]^1),Link(ord[0][i]^1,ord[1][j]);
    22         for(int i=2;i<=pc;++i)if(al[i]==0&&al[i^1]==0){
    23             sz2=sz=0,dfs(i),cnt+=sz&1,blcnt++,g+=(sz2&1)&(sz-sz2&1);
    24             if((sz2&1)&&(sz-sz2&1))sg^=1;
    25             if(sz&1)sg^=2;
    26         }
    27         for(int i=2;i<=pc;++i)if(al[i]&&al[i^1])ok=0;
    28         if(ok)puts(sg?"3":"2");
    29         else puts(m+n&1?"1":"0");
    30         for(int i=2;i<=pc;++i)fir[i]=al[i]=0;pc=ec=ok=1;cnt=blcnt=g=sg=0;
    31     }
    32 }
    View Code

    从博弈论的角度出发如何解释?

    mex函数:mex(X)=X中不存在的最小非负整数。如mex(1,2)=0,mex(0)=1...

    SG函数:为0时代表必败局面,否则为必胜局面。计算方法为mex(通向的所有状态)

    整场游戏如果可以分成若干不相关的部分,那么整场游戏的SG函数值就是每个子游戏的SG函数值异或和。

    在这道题里,子游戏就是一个联通块。

    对于偶偶块,不论怎么选先手都会输,走一步后剩奇数步,那么SG(next)=1,SG=mex(SG(next))=0。

    对于奇奇块,不论怎么选先手都会赢,走一步后剩偶数步,那么SG(next)=0,SG=mex(SG(next))=1。

    对于奇偶块,先手走一步之后,剩余奇偶步都有可能,那么SG(next)={1,0},SG=mex(SG(next))=2。

    计算出每一个联通块的SG函数,异或一下,ans=2+(SG?1:0)

    当然,如果不存在所有硬币都正面朝上的情况,还是要特判的。

  • 相关阅读:
    三大主流负载均衡软件对比(LVS+Nginx+HAproxy)
    nginx 提示the "ssl" directive is deprecated, use the "listen ... ssl" directive instead
    centos安装nginx并配置SSL证书
    hadoop创建目录文件失败
    The server time zone value 'EDT' is unrecognized or represents more than one time zone.
    脚本启动SpringBoot(jar)
    centos做免密登录
    数据库远程连接配置
    Bash 快捷键
    TCP三次握手四次断开
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11824217.html
Copyright © 2011-2022 走看看