博客园 首页 私信博主 显示目录 隐藏目录 管理

矩阵取数问题(dp,高精)

题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n×mn \times mn×m的矩阵,矩阵中的每个元素ai,ja_{i,j}ai,j均为非负整数。游戏规则如下:

  1. 每次取数时须从每行各取走一个元素,共nnn个。经过mmm次后取完矩阵内所有元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值×2i\times 2^i×2i,其中iii表示第iii次取数(从111开始编号);
  4. 游戏结束总得分为mmm次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入输出格式

输入格式:

 

输入文件包括n+1n+1n+1行:

111行为两个用空格隔开的整数nnn和mmm。

2∽n+12\backsim n+12n+1行为n×mn \times mn×m矩阵,其中每行有mmm个用单个空格隔开的非负整数。

 

输出格式:

 

输出文件仅包含111行,为一个整数,即输入矩阵取数后的最大得分。

 

输入输出样例

输入样例#1: 复制
2 3
1 2 3
3 4 2
输出样例#1: 复制
82

说明

NOIP 2007 提高第三题

数据范围:

60%的数据满足:1≤n,m≤301\le n, m \le 301n,m30,答案不超过101610^{16}1016
100%的数据满足:1≤n,m≤801\le n, m \le 801n,m80,0≤ai,j≤10000 \le a_{i,j} \le 10000ai,j1000

 

分析:这道题主要是用来练习dp ,没有涉及高精的问题,因此代码是不能AC的,但是也学习了一下dp的思想,在洛谷上能够过六个点。。。

我们用dp[i][j]代表区间变为【i,j】时,获得的最大分数当区间变为[i][j]时,一定是由【i-1,j】或者是[i,j-1]这两个符合条件的方程式中转移过来的,在第m-(j-i)-1次i取走了当前值。。。

因此状态转移方程就是 dp[i][j]=max(dp[i-1][j]+a[t][i-1]*mypow(len),dp[i][j+1]+a[t][j+1]*mypow(len));

在这要注意一下,当区间长度为1时,它是没有办法把最后一个数字取出来的。因此在这里要在重新加上。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 #define INF 0x3f3f3f3f
 8 #define ll unsigned long long
 9 const int maxn = 100;
10 ll mypow(int k){
11     ll sum=1;
12     for(int i=1; i<=k; i++ ){
13         sum*=2;
14     }
15     return sum;
16 }
17 
18 int n,m;
19 ll ans=0;
20 
21 int main(){
22     cin>>n>>m;
23     int a[maxn][maxn];
24     memset(a,0,sizeof(a));
25     ll dp[maxn][maxn];
26     for( int i=1; i<=n; i++ ){
27         for( int j=1; j<=m; j++ ){
28             scanf("%d",&a[i][j]);
29         }
30     }
31     int t=0;
32 
33     while(t++<n){
34         memset(dp,0,sizeof(dp));
35         for( int i=1; i<=m; i++ ){
36             for( int j=m; j>=i; j-- ){
37                 int len =m-(j-i)-1;
38                
39             }
40         }
41 //        for( int i=1; i<=m; i++ ){
42 //            for( int j=1; j<=m; j++ ){
43 //                cout<<dp[i][j]<<" ";
44 //            }
45 //            cout<<endl;
46 //        }
47         ll rev=0;
48         int i;
49         for( i=1; i<=m; i++ ){
50             ll r=dp[i][i]+a[t][i]*mypow(m);
51             if(r>rev) rev=r;
52         }
53 //        cout<<"rev="<<rev<<endl;
54         ans+=rev;
55     }
56     cout<<ans<<endl;
57     return 0;
58 }

 

posted @ 2019-03-10 15:02  Brave_WTZ  阅读(465)  评论(0编辑  收藏  举报