hdu 5450 Traversal(狀壓dp)
阿新 • • 發佈:2019-01-28
題意比較迷,第一句話的意思是那k個數不存在不用管,出題人的英語.....
但是這個題還是比較難的。
每個點只能到差值1, p, p+2的點,要求每次走數量大於等於3的環,不能重複走完所有點。走完所有點形成環其實相當於,每個點出度入度兩次,要超過3個點意味著不能兩兩成環,更不能自環。
由於最多隻能到達p+2之外的點,所以每個點一定要在p+2的距離只能形成一個環。可以維護當前點i到之前i-p-2之間點的度,考慮向度小於2的點連邊然後轉移,對於之前p+2個點的度小於2的狀態是無效的,因為i+1不可能連向i-p-2。
然後複雜度就是O(n*3^n)。
#include <bits/stdc++.h> using namespace std; const int mod=1e4+7; bool book[105]; int dp[3][531541]; int cur[15], nex[15], N, n, p; int dx[5]; int encode(int *a, int n) { int res=0; for(int i=0; i<n; i++)res=res*3+a[i]; return res; } void decode(int *a, int s, int n) { for(int i=n-1; i>=0; i--) { a[i]=s%3; s/=3; } } void move(int *a, int n) { for(int i=n; i>=1; i--) { a[i]=a[i-1]; } a[0]=0; } void init() { int x, i, k; memset(book, 0, sizeof book); scanf("%d%d", &N, &p); scanf("%d", &k); dx[0]=1, dx[1]=p, dx[2]=p+2; for(i=0; i<k; i++) { scanf("%d", &x); book[x]=1; } } void add(int &u, int v){u=(u+v)%mod;} int solve() { int i, j, e, tar; n=p+2; for(i=0; i<n; i++)cur[i]=2; e=encode(cur, n); memset(dp, 0, sizeof dp); dp[0][e]=1; for(i=0; i<N; i++) { for(j=0; j<=e; j++) { if(dp[0][j]==0)continue; decode(cur, j, n); for(int l=0; l<n; l++)nex[l]=cur[l]; move(nex, n); if(book[i+1]==1) { nex[0]=2; tar=encode(nex, n); if(nex[n]==2)add(dp[1][tar], dp[0][j]); continue; } nex[0]=0; tar=encode(nex, n); if(nex[n]==2)add(dp[1][tar], dp[0][j]); nex[0]=1; for(int l=0; l<3; l++) { int &v=nex[dx[l]]; if(v<2) { v++; tar=encode(nex, n); if(nex[n]==2)add(dp[1][tar], dp[0][j]); v--; } } nex[0]=2; for(int l=0; l<3; l++) { for(int o=l+1; o<3; o++) { int &u=nex[dx[l]], &v=nex[dx[o]]; if(u<2 && v<2) { u++, v++; tar=encode(nex, n); if(nex[n]==2)add(dp[1][tar], dp[0][j]); u--, v--; } } } } for(j=0; j<=e; j++){dp[0][j]=dp[1][j];dp[1][j]=0;} } return dp[0][e]; } int main() { int e=1, t, i, j; cin>>t; while(t--) { init(); printf("Case #%d: %d\n", e++, solve()); } }