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)

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

  • 相关阅读:
    c如何弹出保存路径/保存文件对话框
    c++ 读写txt方法
    windows获取环境变量
    Block UI 获取treelist column值
    MFC中如何弹出选择文件/文件夹对话框(C++)
    What can change the CID of a NX license server?
    spring之AOP
    spring注解开发
    spring配置Bean
    spring之IOC和DI实现
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11824217.html
Copyright © 2011-2022 走看看