zoukankan      html  css  js  c++  java
  • [BZOJ5285][HNOI2018]寻宝游戏

    先贴一段出题人的话:

    当时出题的时候很紧张,是真的紧张,因为觉得实在是太水了。

    ...

    我当时很怕结果出来十几个AC,全场70。然后就再也没人找我出题了。

    当时就不停的想HNOI有什么水题,是不是比我这个更水来安慰自己。

    首先考虑DP,发现如果按照每位依次DP的话不满足无后效性,所以我们从后往前做。

    相当于BFS,列出一个真值表,把8种情况都考虑进去即可。

    这样我们就可以得到。。10分了。

    https://www.cnblogs.com/lzdhydzzh/p/8850109.html

    发现如果全都不强制或者有一位存在不合法情况,都可以直接判掉并剪枝,这样每层最多状态数最多为2。

    手写bitset压64位跑一下可以过。$O(frac{nmq}{64})$

    有点麻烦,看注释吧。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #define rep(i,l,r) for (int i=l; i<=r; i++)
     6 using namespace std;
     7 
     8 typedef unsigned long long ull;
     9 const int N=1010,mod=1e9+7;
    10 int bl,n,m,Q,res,dt,cur,tot;
    11 ull ans,mi[N];
    12 
    13 struct bitset{
    14     ull p[80];
    15     void clear(){ rep(i,0,bl) p[i]=0; }
    16     void read(){
    17         memset(p,0,sizeof(p)); char ch=getchar();
    18         while (!isdigit(ch)) ch=getchar();
    19         for (int i=0; i<m; i++,ch=getchar()) p[i>>6]|=(((ull)(ch-'0'))<<(i&63));//压64位
    20     }
    21 }s[N],f[N],nt,t1,t2,v1,v2,g,c1,c2,que[2][4];
    22 
    23 void init(){
    24     bl=(m-1)>>6; mi[0]=1;
    25     rep(i,1,n) mi[i]=(mi[i-1]<<1)%mod;
    26     memset(nt.p,0,sizeof(nt.p));
    27     for (int i=0; i<m; i++) nt.p[i>>6]|=(1llu<<(i&63));
    28     rep(i,1,n){
    29         s[i].read();
    30         rep(j,0,bl) f[i].p[j]=s[i].p[j]^nt.p[j];
    31     }
    32 }
    33 
    34 int main(){
    35     freopen("bzoj5285.in","r",stdin);
    36     freopen("bzoj5285.out","w",stdout);
    37     scanf("%d%d%d",&n,&m,&Q); init();
    38     while (Q--){
    39         g.read(); dt=ans=cur=0; que[cur][++dt].clear();//0表示必须和询问串一样,1表示不强制
    40         for (int i=n; i; i--){
    41             tot=dt; cur^=1; dt=0;
    42             rep(j,1,tot){
    43                 bool f1=1,f2=1,l1=1,l2=1;
    44                 rep(k,0,bl){
    45                     if (!f1 && !f2) break;
    46                     if (que[cur^1][j].p[k]==nt.p[k]){//如果都不强制的话就不需要具体考虑了
    47                         if (f1) t1.p[k]=nt.p[k];
    48                         if (f2) t2.p[k]=nt.p[k];
    49                         continue;
    50                     }
    51                     //v1为或,v2为且
    52                     if (f1) v1.p[k]=s[i].p[k]&(s[i].p[k]^g.p[k]);//询问串这一位为0,当前串这一位为1
    53                     if (f2) v2.p[k]=g.p[k]&(s[i].p[k]^g.p[k]);//询问串这一位为1,当前串这一位为0
    54                     if (f1 && (v1.p[k]&que[cur^1][j].p[k])!=v1.p[k]) f1=0;//判掉-1
    55                     if (f2 && (v2.p[k]&que[cur^1][j].p[k])!=v2.p[k]) f2=0;//判掉-1
    56                     if (f1) t1.p[k]=que[cur^1][j].p[k]|(s[i].p[k]^v1.p[k]);//生成新的要求,如果本来就不强制则必定不强制,具体根据真值表
    57                     if (f2) t2.p[k]=que[cur^1][j].p[k]|(f[i].p[k]^v2.p[k]);//生成新的要求,如果本来就不强制则必定不强制,具体根据真值表
    58                     if (f1 && t1.p[k]!=nt.p[k]) l1=0;//判断是否全部不强制
    59                     if (f2 && t2.p[k]!=nt.p[k]) l2=0;//判断是否全部不强制
    60                 }
    61                 if (f1){ if (l1) ans=(ans+mi[i-1])%mod; else que[cur][++dt]=t1; }
    62                 if (f2){ if (l2) ans=(ans+mi[i-1])%mod; else que[cur][++dt]=t2; }
    63             }
    64         }
    65         rep(j,1,dt){
    66             bool f1=1;
    67             rep(k,0,bl) if ((que[cur][j].p[k]^nt.p[k])&g.p[k]){ f1=0; break; }//最后对 与 判断一遍是否合法
    68             ans+=f1;
    69         }
    70         printf("%llu
    ",ans);
    71     }
    72     return 0;
    73 }

    上面好像是出题人并不喜欢的暴力解法,很不优美,我们把它扔进垃圾桶。

    正解是把或看成1,与看成0,通过总结规律发现题目可以变成比大小问题。

    https://kelin.blog.luogu.org/solution-p4424

    非常神的想法,代码也很简单,将操作数排序然后看哪个区间是合法的即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rg register int
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=5010,mod=1000000007;
     8 int n,m,q,c[2],a[N],b[N],s[N],t[N],mi[N];
     9 char p[N];
    10 
    11 int up(int x,int y){ x+=y; return (x>=mod)?x-mod:x; }
    12 int dn(int x,int y){ x-=y; return (x<0)?x+mod:x; }
    13 
    14 int main(){
    15     freopen("bzoj5285.in","r",stdin);
    16     freopen("bzoj5285.out","w",stdout);
    17     scanf("%d%d%d",&n,&m,&q);
    18     mi[1]=1; rep(i,2,n+1) mi[i]=(mi[i-1]<<1)%mod;
    19     rep(i,1,m) a[i]=i;
    20     rep(i,1,n){
    21         scanf("%s",p+1); c[0]=0; c[1]=m;
    22         rep(j,1,m) if (p[j]=='1') s[j]=up(s[j],mi[i]); else c[0]++;
    23         for (int j=m; j; j--) b[c[p[a[j]]-48]--]=a[j];
    24         swap(a,b);
    25     }
    26     rep(i,1,m) t[i]=s[a[i]]; t[m+1]=mi[n+1];
    27     while (q--){
    28         scanf("%s",p+1); int x=m+1,y=0;
    29         for (int i=m; i; i--) if (p[a[i]]=='0') { y=i; break; }
    30         rep(i,1,m) if (p[a[i]]=='1') { x=i; break; }
    31         printf("%d
    ",(x<y)?0:dn(t[x],t[y]));
    32     }
    33     return 0;
    34 }
  • 相关阅读:
    【bug】Android版QQ浏览器广告过滤
    -_-#ueditor编辑器chrome浏览器下只能复制最后一行
    -_-#骗子
    -_-#URL区分大小写吗
    -_-#傻傻分不清楚
    -_-#【Canvas】绘制文本
    -_-#【JS Engine】
    -_-#【浏览器】
    -_-#【Canvas】导出在<canvas>元素上绘制的图像
    COGS——C 908. 校园网 || 洛谷——P 2746 [USACO5.3]校园网Network of Schools
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8954335.html
Copyright © 2011-2022 走看看