• [考试反思]1110csp-s模拟测试109:细节


    细节。。。决定成败

    T2数组开小,T3long long没开够。

    而且其实不止这样,考试结束前15分钟发现了好多低错:

    T3双向边没开2倍。dfs没递归调用。T2为了调试bitset开20没改(后来改成了6000,虽说还是错的但是还是好了不少)

    一定要手模几个样例测一下。严格注意数组大小

    最后几天了,一定要注意这种细节了。

    T1:Adore

    状压,dp。

    复杂度$O(mk imes 2^k)$不够优但是足以通过。

     1 #include<cstdio>
     2 int add(int &a,int b){a+=b;if(a>=998244353)a-=998244353;}
     3 int cntbit[1025],m,k,dp[2][1024],E[11],NE[11],ans;
     4 int re(){register char ch=getchar();
     5     while(ch<'0'||ch>'1')ch=getchar();
     6     return ch-'0';
     7 }
     8 int main(){
     9     freopen("adore.in","r",stdin);freopen("adore.out","w",stdout);
    10     for(int i=1;i<1024;++i)cntbit[i]=cntbit[i^i&-i]+1;
    11     scanf("%d%d",&m,&k);m-=3;
    12     int st=0,ths=0,nxt=1;
    13     for(int i=0;i<k;++i)st|=re()<<i;
    14     dp[nxt][st]=1;
    15     while(m--){
    16         ths^=1;nxt^=1;
    17         for(int i=0;i<1<<k;++i)dp[nxt][i]=0;
    18         for(int i=0;i<k;++i)E[i]=NE[i]=0;
    19         for(int i=0;i<k;++i)for(int j=0,x;j<k;++j)x=re(),E[i]|=x<<j,NE[j]|=x<<i;
    20         for(int s=0;s<1<<k;++s)if(dp[ths][s]){
    21             int tst=0,ntst=0;
    22             for(int i=0;i<k;++i)if(s&1<<i)tst^=E[i],ntst^=NE[i];
    23             add(dp[nxt][tst],dp[ths][s]);add(dp[nxt][ntst],dp[ths][s]);
    24         }
    25     }st=0;
    26     for(int i=0;i<k;++i)st|=re()<<i;
    27     for(int i=0;i<1<<k;++i)if(!(cntbit[st&i]&1))add(ans,dp[nxt][i]);
    28     printf("%d
    ",ans);
    29 }
    View Code

    T2:Confess

    手动构造,发现交集大于n的很多。所以采用随机化。注意数组大小。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 bitset<12005>B[6005];
     4 int n,k;char s[6005];
     5 int main(){
     6     freopen("confess.in","r",stdin);freopen("confess.out","w",stdout);
     7     scanf("%d%s",&n,s);
     8     while(s[k])k++;
     9     int cnt=0;
    10     for(int i=0;i<k;++i){
    11         int x=s[i]-33;
    12         for(int j=0;j<6&&cnt<=n<<1;++j)B[1][cnt]=(x&1<<j?1:0),cnt++;
    13     }
    14     for(int I=2;I<=n+1;++I){
    15         scanf("%s",s);
    16         int cnt=0;
    17         for(int i=0;i<k;++i){
    18             int x=s[i]-33;
    19             for(int j=0;j<6&&cnt<=n<<1;++j)B[I][cnt]=(x&1<<j?1:0),cnt++;
    20         }
    21     }
    22     srand(time(0));
    23     while(1){
    24         int a=rand()%(n+1)+1,b=rand()%(n+1)+1;
    25         while(a==b)b=rand()%(n+1)+1;
    26         if((B[a]&B[b]).count()>=n>>1)return printf("%d %d
    ",a,b),0;
    27     }
    28 }
    View Code

    T3:Repulsed

    设dp[i][j]表示距离i这个点j条边的需要灭火器的子节点有多少个。Idp[i][j]表示距离i点有j条边的还没用完的灭火器还能用几次。

    在一棵子树内,互相消除,然后上传。

    如果有的点dp[i][k]>0而Idp[i][0]=0那么就需要申请新的灭火器。

    从远到近依次解决需求,不断上传。最后在1号节点特殊处理:不管剩下多少需求都要直接申请灭火器解决。

    注意Idp数组需要开longlong。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,k,s,fir[100005],l[200005],to[200005],ec,ans,dp[100005][21];long long Idp[100005][21];
     4 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
     5 void dfs(int p,int fa){
     6     dp[p][0]++;
     7     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
     8         dfs(to[i],p);
     9         for(int j=0;j<k;++j)dp[p][j+1]+=dp[to[i]][j],Idp[p][j+1]+=Idp[to[i]][j];
    10     }
    11     while(dp[p][k]>Idp[p][0])Idp[p][0]+=s,ans++;
    12     for(int i=k;~i;--i)for(int j=k-i;~j;--j){
    13         int x=min(1ll*dp[p][i],Idp[p][j]);
    14         dp[p][i]-=x;Idp[p][j]-=x;
    15     }
    16     if(p==1){
    17         int totcnt=0;
    18         for(int i=0;i<=k;++i)totcnt+=dp[p][i];
    19         while(totcnt>0)totcnt-=s,ans++;
    20     }
    21 }
    22 int main(){
    23     freopen("repulsed.in","r",stdin);freopen("repulsed.out","w",stdout);
    24     scanf("%d%d%d",&n,&s,&k);if(s>n)s=n;
    25     for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),link(a,b),link(b,a);
    26     dfs(1,0);printf("%d
    ",ans);
    27 }
    这是错的!!!

     上述算法稍伪。当且仅当需求距离和灭火器距离加和为k或k-1时才会配对,否则就可以上传,以后再匹配。

    上传答案一定不会变差,反而可能找到更优的匹配。

    要注意根节点就可以随意匹配了。

    代码基本没有变。同时时间复杂度也下降到了$O(nk)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,k,s,fir[100005],l[200005],to[200005],ec,ans,dp[100005][21];long long Idp[100005][21];
     4 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
     5 void dfs(int p,int fa){
     6     dp[p][0]++;
     7     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
     8         dfs(to[i],p);
     9         for(int j=0;j<k;++j)dp[p][j+1]+=dp[to[i]][j],Idp[p][j+1]+=Idp[to[i]][j];
    10     }
    11     while(dp[p][k]>Idp[p][0])Idp[p][0]+=s,ans++;
    12     for(int i=k;i>=((p==1)?0:k-1);--i)for(int j=i;~j;--j){
    13         int x=min(1ll*dp[p][j],Idp[p][i-j]);
    14         dp[p][j]-=x;Idp[p][i-j]-=x;
    15     }
    16     if(p==1){
    17         int totcnt=0;
    18         for(int i=0;i<=k;++i)totcnt+=dp[p][i];
    19         while(totcnt>0)totcnt-=s,ans++;
    20     }
    21 }
    22 int main(){
    23     scanf("%d%d%d",&n,&s,&k);
    24     for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),link(a,b),link(b,a);
    25     dfs(1,0);printf("%d
    ",ans);
    26 }
    真正的AC代码

    自家OJ数据水了,去BZOJ1117自测吧。(送个链接)

  • 相关阅读:
    keyset与entryset
    solr4.9r+ Eclipse 4.3+ tomcat 7.5 +winds7(二)
    如何解决This system is not registered with RHN.
    堆和栈的差别(转过无数次的文章)
    墨菲定律、二八法则、马太效应、手表定理、“不值得”定律、彼得原理、零和游戏、华盛顿合作规律、酒与污水定律、水桶定律、蘑菇管理原理、钱的问题、奥卡姆剃刀等13条是左右人生的金科玉律
    atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
    漫谈并发编程(二):java线程的创建与基本控制
    exosip
    PostgreSQL服务端监听设置及client连接方法
    APK反编译。
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11832896.html
Copyright © 2020-2023  润新知