1月赛-吃pizza-正方形简单dp
月赛里的简单题(所以我当然是没做出来啊),要用动态规划实现,有easy版的和normal版的
dp: dp跟递归查不多,关键都是数学里的递推公式(状态转移方程),递归用函数实现;
put
第一行两个正数n,m, k, 分别表示矩阵的行数、矩阵的列数、被吃掉的块数。
接下来有k行,每行有两个数x, y, 表示在x行y列的那块批萨被吃掉了。
easy:(1 <= n, m <= 500, k <= min(500, n*m)) normal::(1 <= n, m <= 5000, k <= min(5000, n*m))
Output
一个整数表示LZDFDSMLL有多少种不同的正方形批萨可以吃。
Sample Input 1
3 3 0
Sample Output 1
14
Sample Input 2
3 3 1 2 2
Sample Output 2
81
想象一下正方形 如果上左上左三个地方都有边长为n的正方形,他们就能拼成一个新n个的正方形,股状态转移方程;
dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])
ps:normal与easy的唯一区别是 总的矩阵规模不同
当是m,n=5000时
ans大概是 5000*5000+4999*4999+. . .+1=n(n+1)(2n+1)/6=5000*5001*10001/6=41 679 167 500
所以要用longlong储存结果
代码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int pic[5500][5500],dp[5500][5500]; int min(int a,int b,int c){ return min(min(a,b),c); } int main(){ memset(pic,0,sizeof(pic)); memset(dp,0,sizeof(dp)); int mk,nk,m,n,k; long long ans=0; scanf("%d%d%d",&m,&n,&k); while(k--){ scanf("%d%d",&mk,&nk); pic[mk][nk]=1; } for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(pic[i][j]==0){ dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1; ans+=dp[i][j]; } printf("%lld",ans); return 0; }