您的位置:首页 > 其它

Codechef A-Maxinum Score 思维题

2018-02-01 19:32 302 查看
题目简介:

You are given N integer sequences A1, A2, ..., AN. Each of these sequences contains N elements. You should pick N elements,
one from each sequence; let's denote the element picked from sequence Ai by Ei. For each i (2 ≤ i ≤ N), Ei should be strictly
greater than Ei-1.
Compute the maximum possible value of E1 + E2 + ... + EN. If it's impossible to pick the elements E1, E2, ..., EN,
print -1 instead.

Input

The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
The first line of each test case contains a single integer N.
N lines follow. For each valid i, the i-th of these lines contains N space-separated integers Ai1, Ai2, ..., AiN denoting the elements
of the sequence Ai.

Output

For each test case, print a single line containing one integer — the maximum sum of picked elements.

Constraints

1 ≤ T ≤ 10
1 ≤ N ≤ 700
1 ≤ sum of N in all test-cases ≤ 3700
1 ≤ Aij ≤ 109 for each valid ij

Subtasks

Subtask #1 (18 points): 1 ≤ Aij ≤ N for each valid ij
Subtask #2 (82 points): original constraints

Example

Input:

1
3
1 2 3
4 5 6
7 8 9

Output:

18

Explanation

Example case 1: To maximise the score, pick 3 from the first row, 6 from the second row and 9 from the third row. The resulting sum is E1+E2+E3 =
3+6+9 = 18.
这道题目就是给一个二维数组,每行选一个元素,从第一行开始严格递增,求选择的序列之和的最大值是多少。

我一开始以为是 dp , 结果一直 Time Limit Exceed , 700*700*700的操作.....

不好处理的就是,当前选好的递增序列可能在某一行,不能继续维持严格递增了,就要回去更改,在前一行选择另一个元素。。。。。最关键的就在最后一行了,最后一行的最大值一定是要选的,然后之前选择的值也一定要小于最后一行的最大值,这样就可以了,倒着加,从后面往前面找,在当前行选的 cur ,选择上一行的小于cur 的最大值,这样就保证严格递减( 从高往低 ) , 而且不用改。思维题。

注意数据类型 long long 

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std ;
typedef long long LL ;
LL a[705][705] ;

int main(){
int T , n ;
scanf( "%d" , &T ) ;
while( T-- ){
scanf( "%d" , &n ) ;
int i , j , flag ;
for( i = 1 ; i <= n ; ++i ){
for( j = 1 ; j <= n ; ++j )
scanf( "%lld" , &a[i][j] ) ;
sort( a[i]+1 , a[i]+n+1 ) ; // 先排好序,从后面更大的开始筛选
}
LL ans = a

, cur = ans ;
for( i = n-1 ; i >= 1 ; --i ){ // 从高往低找
flag = 0 ;
for( j = n ; j >= 1 && a[i][j] >= cur ; --j ) ; // 找上一行小于 cur 的最大值
flag = a[i][j] < cur ;
if( flag ) // 如果找得到更小的最大值 , ans 累加,更新当前行最大值
ans += a[i][j] , cur = a[i][j] ;
else break ; // 在第 i 行找不到继续从高往低递减的值,序列不存在
}
printf( flag == 0 ? "-1\n" : "%lld\n" , ans ) ;
}
return 0 ;
}


我一开始就是用 dp 做的,自己测的简单数据都没错,然后一直超时,三重循环。我也不知道原来写的对不对,如有错误,敬请指正。(请忽略超时 ,emm)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std ;
typedef long long LL ;
LL dp[705][705] , a[705][705] ;
bool cmp( LL a , LL b ){ return a > b ; }

int main(){
int T , n ;
scanf( "%d" , &T ) ;
while( T-- ){
memset( dp , 0 , sizeof( dp ) ) ;
scanf( "%d" , &n ) ;
int OK = 0 , i , j , k ;
for( i = 1 ; i <= n ; ++i ){
for( int j = 1 ; j <= n ; ++j )
scanf( "%lld" , &a[i][j] ) ;

aaf7
sort( a[i]+1 , a[i]+n+1 , cmp ) ;
}
for( i = 1 ; i <= n ; ++i ){ // 每一行
OK = 0 ;
for( j = 1 ; j <= n ; ++j ){ // 每一个元素
if( a[i][j] <= a[i-1]
) break ; // 后面的更没希望了
for( k = 1 ; k <= n ; ++k ) // 和上一行的元素做对比
if( ( i == 1 || dp[i-1][k] ) && a[i][j] > a[i-1][k] ) // 如果上一行的这个数在某个连续的递增序列中
dp[i][j] = max( dp[i][j] , dp[i-1][k] + a[i][j] ) , OK = 1 ;
}
if( !OK ) break ;
}
if( !OK ) { cout << "-1" << endl ; continue ; }
LL ans = dp
[1] ;
for( i = 2 ; i <= n ; ++i )
ans = max( ans , dp
[i] ) ;
printf( ans == 0 ? "-1\n" : "%lld\n" , ans ) ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: