每日一题 day30 打卡
Analysis
f[i][j][p][q]表示他们走到(i,j),且两人魔瓶内魔液量的差为p时的方法数。q=0表示最后一步是小a走的,q=1表示最后一步是uim走的。题目中说魔瓶的容量为k,实际上就是动归时p需要对k+1取余数,即p只有0~k,k+1种可能。答案为所有f[i][j][0][1]的和。
动归方程如下:(为了方便已经令k=k+1)
f[i][j][p][0]+=f[i-1][j][(p-mapp[i][j]+k)%k][1] (i-1>=1)
f[i][j][p][0]+=f[i][j-1][(p-mapp[i][j]+k)%k][1] (j-1>=1)
f[i][j][p][1]+=f[i-1][j][(p+mapp[i][j])%k][0] (i-1>=1)
f[i][j][p][1]+=f[i][j-1][(p+mapp[i][j])%k][0] (j-1>=1)
还有每个格子都有可能作为小a的起始格子,所以初始时对于所有i、j,f[i][j][mapp[i][j]][0]=1。
算法复杂度o(n*m*k)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 800+10 6 #define mod 1000000007 7 using namespace std; 8 inline int read() 9 { 10 int x=0; 11 bool f=1; 12 char c=getchar(); 13 for(; !isdigit(c); c=getchar()) if(c=='-') f=0; 14 for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0'; 15 if(f) return x; 16 return 0-x; 17 } 18 inline void write(long long x) 19 { 20 if(x<0){putchar('-');x=-x;} 21 if(x>9)write(x/10); 22 putchar(x%10+'0'); 23 } 24 int n,m,k; 25 int map[maxn][maxn]; 26 int dp[maxn][maxn][20][2]; 27 int main() 28 { 29 n=read();m=read();k=read(); 30 k++; 31 for(int i=1;i<=n;i++) 32 for(int j=1;j<=m;j++) 33 { 34 map[i][j]=read(); 35 dp[i][j][map[i][j]][0]=1; 36 } 37 long long ans=0; 38 for(int i=1;i<=n;i++) 39 for(int j=1;j<=m;j++) 40 for(int p=0;p<=k;p++) 41 { 42 dp[i][j][p][0]=(dp[i][j][p][0]+dp[i-1][j][(p-map[i][j]+k)%k][1])%mod; 43 dp[i][j][p][0]=(dp[i][j][p][0]+dp[i][j-1][(p-map[i][j]+k)%k][1])%mod; 44 dp[i][j][p][1]=(dp[i][j][p][1]+dp[i-1][j][(p+map[i][j])%k][0])%mod; 45 dp[i][j][p][1]=(dp[i][j][p][1]+dp[i][j-1][(p+map[i][j])%k][0])%mod; 46 } 47 for(int i=1;i<=n;i++) 48 for(int j=1;j<=m;j++) 49 ans=(ans+dp[i][j][0][1])%mod; 50 write(ans); 51 return 0; 52 }
请各位大佬斧正(反正我不认识斧正是什么意思)