P1005 矩阵取数游戏

斯德哥尔摩

2018-10-22 23:52:16

Personal

[P1005 矩阵取数游戏](https://www.luogu.org/problemnew/show/P1005) 首先发现每一行怎么选对于其他的行没有任何影响。 那就单独把每一行提出来,开始区间$DP$。 设$dp[i][j]$代表取区间$[i,j]$的最大值,$val[i]$为当前行的每个数。 然后我们考虑,对于每一个新的$dp[i][j]$,有两种情况: 1. 先取前面的$val[i]$,再取剩下的$dp[i+1][j]$即$[i+1,j]$的最大值: $$dp[i][j]=2\times dp[i+1][j]+2\times val[i]$$ 即:把接下来取的所有数乘上$2$,也就是把接下来取的所有数从$x\times 2^{i}$变为$x\times 2^{i+1}$。 即:每次取都把之前的翻一倍,然后当前取的值$val[i]$要乘上$2$。 2. 先取后面的$val[j]$,再取剩下的$dp[i][j-1]$即$[i,j-1]$的最大值,同理: $$dp[i][j]=2\times dp[i][j-1]+2\times val[j]$$ 到此,方程推完了: $$dp[i][j]=\max\left\{\begin{array}{}2\times dp[i+1][j]+2\times val[i]\\2\times dp[i][j-1]+2\times val[j]\end{array}\right.$$ 然而,这个题的最终答案炒鸡大——炸$long\ long$。。。 于是,高精? 对我来说是$\tan(\frac{\pi}{2}+k\pi),k\in Z$。。。 而且据说高精写的丑会$TLE$。。。 怎么办? $\underline\ \ \underline\ int128$! 这玩意好啊! 然后就没了。。。 附代码: ```cpp #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 85 using namespace std; int n,m; __int128 ans=0; __int128 val[MAXN][MAXN],dp[MAXN][MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void write(__int128 x){ if(x>9)write(x/10); putchar(x%10+'0'); } __int128 solve(int x){ memset(dp,0,sizeof(dp)); for(int i=0;i<=m;i++) for(int j=1;j+i<=m;j++) dp[j][j+i]=max(dp[j+1][j+i]*2+val[x][j]*2,dp[j][j+i-1]*2+val[x][j+i]*2); return dp[1][m]; } void work(){ for(int i=1;i<=n;i++)ans+=solve(i); write(ans);putchar('\n'); } void init(){ n=read();m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) val[i][j]=read(); } int main(){ init(); work(); return 0; } ```