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

细节。。。决定成败

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

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

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

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

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

 

T1:Adore

状压,dp。

复杂度$O(mk \times 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\n",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\n",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\n",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\n",ans);
26 }
真正的AC代码

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

 

 

posted @ 2019-11-11 09:21  DeepinC  阅读(476)  评论(4编辑  收藏  举报