zoukankan      html  css  js  c++  java
  • NOIP2007 矩阵取数游戏

    题意简化

    传送门
    给定一个n*m的矩阵,在每一行中取m次数,每次取数只能从行首或尾取数,第i次取数的贡献是 (2^i*该点值) ,操作n行,求最大答案
    n,m<=80

    题解

    不难发现行与行之间是完全独立的,所以单独处理每一行就好了
    考虑区间DP
    设 dp[i][j] 表示区间i~j的答案最大值
    则有 (dp[i][j]=max(num[i]*q[m-(i-j)]+dp[i+1][j],num[j]*q[m-(i-j)]+dp[i][j-1]))
    其中 m-(r-l) 是当前操作次数 (想想为什么)
    num表示原数,q[i]表示 2^i 我也不知道为什么要用q,或许是因为快速幂习惯了???

    然后记搜一下就好了

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    #define ll long long
    #define get getchar()
    #define in inline
    in int read()
    {
    	int t=0; char ch=get;
    	while(ch<'0' || ch>'9') ch=get;
    	while(ch<='9' && ch>='0') t=t*10+ch-'0',ch=get;
    	return t;
    }
    __int128 n,m,dp[101][101],q[80],num[1001],ans;
    in __int128 dfs(int l,int r)
    {
    	if(dp[l][r]!=-1)return dp[l][r];
    	if(l!=r)dp[l][r]=max(num[l]*q[m-(r-l)]+dfs(l+1,r),num[r]*q[m-(r-l)]+dfs(l,r-1)); //当前区间未知
    	else
    		dp[l][r]=num[l]*q[m]; //当前区间只剩下一个数了
    	return dp[l][r];
    }
    in void out()
    {
    	char s[1001];int tot;
    	while(ans)
    	{
    		s[++tot]=(ans%10)+'0';
    		ans/=10;
    	}
    	for(re int i=tot;i>=1;i--)putchar(s[i]);
    	cout<<endl;
    } //我也不知道为什么,好像int128只能这样输出(雾???
    int main()
    {
    	n=read(),m=read(),q[0]=1;
    	for(re int i=1;i<=m;i++)q[i]=q[i-1]*2;
    	for(re int i=1;i<=n;i++)
    	{
    		for(re int j=1;j<=m;j++)num[j]=read();
    		memset(dp,-1,sizeof(dp));
    		ans+=dfs(1,m);
    	}
    	if(ans==0)
    		cout<<0;
    	else
    		out();
    	return 0;
    }
    
    
    嗯,就这样了...
  • 相关阅读:
    231. Power of Two
    204. Count Primes
    205. Isomorphic Strings
    203. Remove Linked List Elements
    179. Largest Number
    922. Sort Array By Parity II
    350. Intersection of Two Arrays II
    242. Valid Anagram
    164. Maximum Gap
    147. Insertion Sort List
  • 原文地址:https://www.cnblogs.com/yzhx/p/10700069.html
Copyright © 2011-2022 走看看