【NOIP/CSP2019】D2T1 Emiya 家今天的飯

這個D2T1有點難度啊python

原題:ios

 

 

花了我一下午的時間,做爲D2T1的確反常ide

條件很奇怪,感受不太直觀,因而看數據範圍先寫了個暴力優化

寫暴力的時候我就注意到了以前沒有仔細想過的點,烹飪方式必須不一樣spa

雖然a很大,可是n只有100,即總菜數比較小.net

並且雖然m和a都很大,可是一種方法只能作一道菜,即選一種食材設計

因此搜索枚舉每種方法選哪一種食材,最後檢查方案是否知足條件code

這樣能夠拿到32分blog

須要注意到一點很關鍵的性質ci

無論什麼方案,最多隻有一個食材能超過n/2,看到n/2要敏感

那麼若是無視n/2的限制,直接dp就vans了,接下來只須要去掉不合法的方案

枚舉哪種食材超過n/2,能夠發現此時食材只有兩種,枚舉到的食材和其餘的食材

須要表達的狀態數大大減小

設計狀態,f[i][j][k]表示直到第i種方式,總共選了j道菜,其中k道菜用當前枚舉食材

這樣能夠拿到82分

而後就不會了233

這個遞推又沒有決策,咋優化啊

本着單個題目思考時間不能過長的原則,觀摩了python96的題解:

https://blog.csdn.net/weixin_37517391/article/details/103110646

馬上點化233

確實不太好想,果真適時看題解效率更高

咱們記錄狀態的時候沒必要記錄兩類食材的數量,只需記錄兩者差值便可

只要差值相同,不一樣的數量對於合法性的判斷都是等價的

那麼之前的3維dp就優化到2維,能夠ac了

 

代碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define LL long long
 8 const int mo=998244353;
 9 int rd(){int z=0,mk=1;  char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
11     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
12     return z*mk;
13 }
14 int n,m,a[110][2100];
15 LL ans=0;
16 int cnt[2100];
17 LL s[110];
18 LL f7[110][110][110];
19 LL f[110][210];
20 bool chck(int x){
21     if(!x)  return false;
22     //注意x=0時必須特判,由於此時cnt也全是0,下面條件不會成立
23     for(int i=1;i<=m;++i)if(cnt[i]>x/2)  return false;
24     return true;
25 }
26 void dfs(int x,int y,LL z){
27     if(x==n+1){
28         if(chck(y))  ans=(ans+z)%mo;
29         return ;
30     }
31     dfs(x+1,y,z);
32     for(int i=1;i<=m;++i)if(a[x][i]){
33         ++cnt[i];
34         dfs(x+1,y+1,z*a[x][i]%mo);
35         --cnt[i];
36     }
37 }
38 LL gan(int x){
39     memset(f7,0,sizeof(f7));
40     f7[0][0][0]=1;
41     for(int i=1;i<=n;++i)for(int j=0;j<=i;++j)for(int k=0;k<=j;++k){
42         f7[i][j][k]=f7[i-1][j][k];
43         if(j && k)  f7[i][j][k]=(f7[i][j][k]+f7[i-1][j-1][k-1]*a[i][x]%mo)%mo;
44         if(j)  f7[i][j][k]=(f7[i][j][k]+f7[i-1][j-1][k]*(s[i]-a[i][x])%mo)%mo;
45     }
46     LL bwl=0;
47     for(int i=1;i<=n;++i)for(int j=i/2+1;j<=i;++j)  bwl=(bwl+f7[n][i][j])%mo;
48     return bwl;
49 }
50 LL ganisok(int x){
51     memset(f,0,sizeof(f));
52     f[0][n]=1;
53     for(int i=1;i<=n;++i)for(int j=0;j<=n+n;++j){
54         f[i][j]=f[i-1][j];
55         if(j)  f[i][j]=(f[i][j]+f[i-1][j-1]*a[i][x]%mo)%mo;
56         if(j<n+n)  f[i][j]=(f[i][j]+f[i-1][j+1]*(s[i]-a[i][x]%mo))%mo;
57     }
58     LL bwl=0;
59     for(int i=n+1;i<=n+n;++i)  bwl=(bwl+f[n][i])%mo;
60     return bwl;
61 }
62 int main(){
63     //freopen("ddd.in","r",stdin);
64     cin>>n>>m;
65     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)  a[i][j]=rd();
66     if(n<=10 && m<=3){
67         dfs(1,0,1);
68         cout<<ans<<endl;
69     }
70     else if(n<=40 && m<=500){
71         for(int i=1;i<=n;++i){
72             s[i]=0;
73             for(int j=1;j<=m;++j)  s[i]=(s[i]+a[i][j])%mo;
74         }
75         LL bwl=1;
76         for(int i=1;i<=n;++i)  bwl=bwl*(s[i]+1)%mo;
77         bwl-=1;
78         for(int i=1;i<=m;++i)  bwl=(bwl-gan(i))%mo;
79         cout<<(bwl%mo+mo)%mo<<endl;
80     }
81     else{
82         for(int i=1;i<=n;++i){
83             s[i]=0;
84             for(int j=1;j<=m;++j)  s[i]=(s[i]+a[i][j])%mo;
85         }
86         LL bwl=1;
87         for(int i=1;i<=n;++i)  bwl=bwl*(s[i]+1)%mo;
88         bwl-=1;
89         for(int i=1;i<=m;++i)  bwl=(bwl-ganisok(i))%mo;
90         cout<<(bwl%mo+mo)%mo<<endl;
91     }
92     return 0;
93 }
View Code
相關文章
相關標籤/搜索