[考試反思]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自測吧。(送個鏈接)

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM