ACM暑期集训19

写两道DP的题解:

A - Max Sum Plus Plus

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem. 

Given a consecutive number sequence S 1, S 2, S 3, S 4 ... S x, ... S n (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ S x ≤ 32767). We define a function sum(i, j) = S i + ... + S j (1 ≤ i ≤ j ≤ n). 

Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + ... + sum(i m, j m) maximal (i x ≤ iy ≤ j x or i x ≤ j y ≤ j x is not allowed). 

But I`m lazy, I don't want to write a special-judge module, so you don't have to output m pairs of i and j, just output the maximal summation of sum(i x, j x)(1 ≤ x ≤ m) instead. ^_^ 

Input

Each test case will begin with two integers m and n, followed by n integers S 1, S2, S 3 ... S n
Process to the end of file. 

Output

Output the maximal summation described above in one line. 

Sample Input

1 3 1 2 3
2 6 -1 4 -2 3 -2 3

Sample Output

6
8

f[i][j]表示前i个数(第i个数必须取)组成j个不相交子段所能取得的最大和        

f[i][j] = max(f[i-1][j]+a[i], f[k][j-1] + a[i]) (0<k<i-1)

对于f[k][j-1] 其实可以提前维护前缀最大,这样降低了时间复杂度

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;

typedef long long ll;
const int inf=0x3f3f3f3f3f;
const int maxn=1e6+10;
int dp[maxn];
int ma[maxn];
int a[maxn];
int main()
{
    int n,m;
    while (~scanf("%d%d",&m,&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            dp[i]=0;
            ma[i]=0;
        }
        dp[0]=0;
        ma[0]=0;
        int maa;
        for(int i=1;i<=m;i++)
        {
           maa=-inf;
            for(int j=i;j<=n;j++)
            {
                dp[j]=max( dp[j-1]+a[j],ma[j-1]+a[j] );
                ma[j-1]=maa;
                maa=max(maa,dp[j]);
            }
        }
        printf("%d\n",maa);
    }
    return 0;
}

B - Number String

The signature of a permutation is a string that is computed as follows: for each pair of consecutive elements of the permutation, write down the letter 'I' (increasing) if the second element is greater than the first one, otherwise write down the letter 'D' (decreasing). For example, the signature of the permutation {3,1,2,7,4,6,5} is "DIIDID". 

Your task is as follows: You are given a string describing the signature of many possible permutations, find out how many permutations satisfy this signature. 

Note: For any positive integer n, a permutation of n elements is a sequence of length n that contains each of the integers 1 through n exactly once. 

Input

Each test case consists of a string of 1 to 1000 characters long, containing only the letters 'I', 'D' or '?', representing a permutation signature. 

Each test case occupies exactly one single line, without leading or trailing spaces.

Proceed to the end of file. The '?' in these strings can be either 'I' or 'D'. 

Output

For each test case, print the number of permutations satisfying the signature on a single line. In case the result is too large, print the remainder modulo 1000000007.

Sample Input

II
ID
DI
DD
?D
??

Sample Output

1
2
2
1
3
6

        
  

Hint

Permutation {1,2,3} has signature "II".
Permutations {1,3,2} and {2,3,1} have signature "ID".
Permutations {3,1,2} and {2,1,3} have signature "DI".
Permutation {3,2,1} has signature "DD".
"?D" can be either "ID" or "DD".
"??" gives all possible permutations of length 3.

分析:

那么我们设dp[i][j]为长度为i,末尾数字是j的序列的个数。 
如果此位和前一位的关系为I,即前一位小于此位,那么前一位可能是任意小于j的数字。所以dp[i][j]=dp[i-1][j-1]+dp[i-1][j-2]+…+dp[i-1][1]。 
如果此位和前一位的关系为D,即前一位大于此位,那么前一位可能是任意大于等于j的数字。所以dp[i][j]=dp[i-1][i-1]+dp[i-1][i-2]+…+dp[i-1][j]。

那么这样做,每次j最大只循环到i的话,大于i小于n的数是如何能排到前面去的?而且是怎么做到整个数列没有重复元素的?

就比如下一位是D,我们前面排好了2 1 3,现在所求为dp[4][2],我们的方法是把数列里面大于等于2的全部加1,小于2的不变,再把2排到最后,这样并不会改变前面排好序列的大小关系。那么我们得到的序列就是3 1 4 2。

这样既不会出现相同元素,也可以解释为什么这么递推可以把大于当前循环最大值i的数排在前面。

当然如果直接进行循环是个n三次方的复杂度。所以我们需要优化前缀和降低复杂度为n方。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;

typedef long long ll;
const int inf=0x3f3f3f3f3f;
const int maxn=1e6+10;
int dp[maxn];
int ma[maxn];
int a[maxn];
int main()
{
    int n,m;
    while (~scanf("%d%d",&m,&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            dp[i]=0;
            ma[i]=0;
        }
        dp[0]=0;
        ma[0]=0;
        int maa;
        for(int i=1;i<=m;i++)
        {
           maa=-inf;
            for(int j=i;j<=n;j++)
            {
                dp[j]=max( dp[j-1]+a[j],ma[j-1]+a[j] );
                ma[j-1]=maa;
                maa=max(maa,dp[j]);
            }
        }
        printf("%d\n",maa);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41383801/article/details/81638460