題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6578
題目大意:長度為\(n\)的數組要求分別填入\(\{0,1,2,3\}\)四個數中的任意一個,有\(m\)個限制條件:區間\([l,r]\)中出現的數字種數恰好為\(x\),求方案數
題解:f[i][j][k][cur]表示四個數最后出現的位置經過排序后為\(i,j,k,cur\)的方案數,暴力轉移即可,其中最后一維需要滾動數組節省空間
對於限制條件可以用vector存下來,每次循環對右端點為當前點的限制條件進行判斷即可
雖然要套四個\(for\),但是由於有順序限制,所以執行次數大約為\(\frac{n^4}{24}\),加上本題的運算簡單,常數較小,因此基本不會出現TLE的情況
但是還是要吐槽一句出題人把這場比賽的時間設的好死啊...開個3s應該也不至於放假算法過吧orz

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 101 4 #define mp make_pair 5 #define MOD 998244353 6 int T,n,m,l,r,x,f[N][N][N][2],ans; 7 vector<pair<int,int>>d[N]; 8 void init() 9 { 10 ans=0; 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=n;i++) 13 { 14 d[i].clear(); 15 d[i].push_back(mp(i,1)); 16 } 17 for(int i=1;i<=m;i++) 18 { 19 scanf("%d%d%d",&l,&r,&x); 20 d[r].push_back(mp(l,x)); 21 } 22 memset(f,0,sizeof(f)); 23 f[0][0][0][0]=1; 24 for(int cur=1;cur<=n;cur++) 25 { 26 int o=cur&1; 27 for(int i=0;i<=cur;i++) 28 for(int j=i;j<=cur;j++) 29 for(int k=j;k<=cur;k++) 30 f[i][j][k][o]=0; 31 for(int i=0;i<=cur;i++) 32 for(int j=i;j<=cur;j++) 33 for(int k=j;k<=cur;k++) 34 { 35 (f[j][k][cur-1][o]+=f[i][j][k][o^1])%=MOD; 36 (f[i][k][cur-1][o]+=f[i][j][k][o^1])%=MOD; 37 (f[i][j][cur-1][o]+=f[i][j][k][o^1])%=MOD; 38 (f[i][j][k][o]+=f[i][j][k][o^1])%=MOD; 39 } 40 for(int i=0;i<=cur;i++) 41 for(int j=i;j<=cur;j++) 42 for(int k=j;k<=cur;k++) 43 for(auto pi:d[cur]) 44 { 45 l=pi.first,r=cur,x=pi.second; 46 if((i>=l)+(j>=l)+(k>=l)+(cur>=l)!=x) 47 f[i][j][k][o]=0; 48 } 49 } 50 for(int i=0;i<=n;i++) 51 for(int j=i;j<=n;j++) 52 for(int k=j;k<=n;k++) 53 (ans+=f[i][j][k][n&1])%=MOD; 54 printf("%d\n",ans); 55 } 56 int main() 57 { 58 scanf("%d",&T); 59 while(T--)init(); 60 }
代碼中對vector的初始化其實是沒必要額外push_back的,寫的時候為了保險就加上去了(雖然差點導致TLE)
這竟然是我博客里的第一道純DP題...?