2016 Multi-University Training Contest 5题解报告

此文章可以使用目录功能哟↑(点击上方[+])

话说浙江理工大学是不是很喜欢序列和dp,着实让我有点智商捉急...

2016 Multi-University Training Contest 5官方题解

链接→2016 Multi-University Training Contest 5

 Problem 1001 ATM Mechine

Accept: 0    Submit: 0
Time Limit: 6000/3000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

Alice is going to take all her savings out of the ATM(Automatic Teller Machine). Alice forget how many deposit she has, and this strange ATM doesn't support query deposit. The only information Alice knows about her deposit is the upper bound is K RMB(that means Alice's deposit x is a random integer between 0 and K (inclusively)). 

Every time Alice can try to take some money y out of the ATM. if her deposit is not small than y, ATM will give Alice y RMB immediately. But if her deposit is small than y, Alice will receive a warning from the ATM. 

If Alice has been warning more then W times, she will be taken away by the police as a thief.

Alice hopes to operate as few times as possible.

As Alice is clever enough, she always take the best strategy. 

Please calculate the expectation times that Alice takes all her savings out of the ATM and goes home, and not be taken away by the police.

 Input

The input contains multiple test cases.

Each test case contains two numbers K and W.

1≤K,W≤2000

 Output

For each test case output the answer, rounded to 6 decimal places.

 Sample Input

1 1
4 2
20 3

 Sample Output

1.000000
2.400000
4.523810

 Problem Idea

解题思路:

【题意】
这题的意思还是比较费解的

Alice忘记自己在银行里存了多少钱,只记得是闭区间[0,k]内的一个整数

每次取钱,Alice会取y RMB的钱,如果余额足够则被取出,否则会被警告一次

若警告次数超过w次,Alice就会被警察抓走

在不被警察抓走的前提下,Alice采取最优策略,问期望尝试取钱多少次能够取完Alice存的所有钱


【类型】
概率dp

【分析】
首先,我们知道ZSTU偏爱dp

那么无疑,此题为概率dp

令dp[i][j]表示Alice知道自己的存款范围是[0,i],还可以被警告j次的期望值

对于当前存款范围[0,i],Alice取y RMB的时候,会面临两种情况:

①余额不足,即

此时会被警告一次

但相对的,我们可以缩小存款范围[0,y-1]

因为y RMB是取不出的,那存款最多为y-1 RMB,这点显然

所以,dp[i][j]与dp[y-1][j-1]有关

②余额足够,即≥y

此时不会被警告

而且还能缩小存款范围[0,i-y]

因为原来存款最多可能有i RMB,现在取走了y RMB,那么最多还剩i-y RMB

所以,dp[i][j]还和dp[i-y][j]有关

再者,我们要先确定一下递推式,P(存款

由递推式来看,上述我们已经分析出了E(存款

那我们还需要再求解一下P(存款

因为当前存款范围是[0,i],那么,存款可能就是0~i这i+1种情况,那小于y的显然就0~y-1这y种情况,大于等于y的则是y~i这i-y+1种

那么可以得到状态转移方程


貌似官方题解的状态转移方程写错了

另外,Alice采取二分策略,故在最坏情况下至多被警告

于是W:=min(W,11)就可以了。

【时间复杂度&&优化】
O(K^2*min{W,11})

题目链接→HDU 5781 ATM Mechine

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 2001;
const int M = 12;
const double inf = 1e9;
const int mod = 1000000007;
double dp[N][M];
int main()
{
    int k,w,i,j,y;
    for(i=1;i

 Problem 1003 Divide the Sequence

Accept: 0    Submit: 0
Time Limit: 5000/2500 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

Alice has a sequence A, She wants to split A into as much as possible continuous subsequences, satisfying that for each subsequence, every its prefix sum is not small than 0.

 Input

The input consists of multiple test cases. 

Each test case begin with an integer n in a single line.

The next line contains n integers A1,A2⋯An.

1≤n≤1e6

−10000≤A[i]≤10000

You can assume that there is at least one solution.

 Output

For each test case, output an integer indicates the maximum number of sequence division.

 Sample Input

6
1 2 3 4 5 6
4
1 2 -3 0
5
0 0 0 0 0

 Sample Output

6
2
5

 Problem Idea

解题思路:

【题意】
给你一个序列A,问你最多能够分成多少个连续子序列,使得每个子序列的所有前缀和均不小于0


【类型】
贪心

【分析】
真是被自己蠢哭

貌似是以前被最长上升子序列和最长上升子串给搞中毒了

看到题目说连续子序列,不是连续子串,然后brabra以为不连续,搞半天不会搞

然后队友说不是连续的吗?无爱,自己太蠢,然后就秒A了

因为题目说子序列的所有前缀和都不小于0

(PS:理解一下前缀,对于子序列2,3,-7,它的前缀包括①2;②2,3;③2,3,-7)

所以从序列尾部往前扫,一旦某项为负,那我必须往前求和,直到和不小于0,那么这一段就是一段满足题意的连续子序列,就是那么暴力(贪心)

【时间复杂度&&优化】
O(n)

题目链接→HDU 5783 Divide the Sequence

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 5005;
const int inf = 1000000007;
const int mod = 1000000007;
__int64 s[N];
int main()
{
    int n,i,ans;
    while(~scanf("%d",&n))
    {
        ans=0;
        for(i=0;i=0;i--)
            if(s[i]<0)
                s[i-1]+=s[i];
            else
                ans++;
        printf("%d\n",ans);
    }
    return 0;
}

 Problem 1011 Two

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

Alice gets two sequences A and B. A easy problem comes. How many pair of sequence A' and sequence B' are same. For example, {1,2} and {1,2} are same. {1,2,4} and {1,4,2} are not same. A' is a subsequence of A. B' is a subsequence of B. The subsequnce can be not continuous. For example, {1,1,2} has 7 subsequences {1},{1},{2},{1,1},{1,2},{1,2},{1,1,2}. The answer can be very large. Output the answer mod 1000000007.

 Input

The input contains multiple test cases.

For each test case, the first line cantains two integers N,M(1≤N,M≤1000). The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.


 Output

For each test case, output the answer mod 1000000007.

 Sample Input

3 2
1 2 3
2 1
3 2
1 2 3
1 2

 Sample Output

2
3

 Problem Idea

解题思路:

【题意】
给你两个序列A和B

问两个序列有多少个子序列一样

例如{1,2}与{1,2}一样,{1,2,4}与{1,4,2}不一样


【类型】
最长公共子序列变形

【分析】
很显然的一道DP题

求的是公共子序列对数

令dp[i][j]表示A序列前i个数和B序列前j个数的相同子序列对有多少个

状态转移方程为dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+(a[i]==b[j]?dp[i-1][j-1]+1:0)

怎么理解呢?对于序列A,当加入第i个数时,它增加了长度为j的序列B中与该数相同的数,序列B同理

2016 Multi-University Training Contest 5题解报告_第1张图片

2016 Multi-University Training Contest 5题解报告_第2张图片

2016 Multi-University Training Contest 5题解报告_第3张图片

2016 Multi-University Training Contest 5题解报告_第4张图片

还有增加的取决于a[i]是否等于b[j],若相等,则增加了dp[i-1][j-1]+1对,这个1就是(a[i],b[j])这对,dp[i-1][j-1]则是有共同前缀的对

dp还是要好好理解一下,毕竟还是比较常见,不会很吃亏,本人就是一个很好的例子,总是在dp上吃亏

【时间复杂度&&优化】
O(n^2)

题目链接→HDU 5791 Two

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1005;
const int M = 5005;
const int inf = 1000000007;
const int mod = 1000000007;
int a[N],b[N];
__int64 dp[N][N];
int main()
{
    int n,m,i,j;
    while(~scanf("%d%d",&n,&m))
    {
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(i=1;i<=m;i++)
            scanf("%d",&b[i]);
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                dp[i][j]=(dp[i-1][j]+dp[i][j-1]+(a[i]==b[j]?1:mod-dp[i-1][j-1]))%mod;
        printf("%I64d\n",dp[n][m]);
    }
    return 0;
}

 Problem 1012 World is Exploding

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤aAd.

 Input

The input consists of multiple test cases. 

Each test case begin with an integer n in a single line.

The next line contains n integers A1,A2⋯An.

1≤n≤50000

0≤Ai≤1e9


 Output

For each test case,output a line contains an integer.


 Sample Input

4
2 4 1 3
4
1 2 3 4

 Sample Output

1
0

 Problem Idea

解题思路:

【题意】
给你一个序列A,选出四个下标不同的元素,下标记为a,b,c,d

a≠b≠c≠d,1≤a

满足AaAd

问能找到多少个这样的四元组(a,b,c,d)


【类型】
树状数组应用

【分析】
因为aAd

所以我们暂时称(a,b)为递增对,(c,d)为递减对

题目就转化成递增对*递减对-重复对

重复对包括如下四种:

①b,c一致

②a,c一致

2016 Multi-University Training Contest 5题解报告_第5张图片

③b,d一致

2016 Multi-University Training Contest 5题解报告_第6张图片

④a,d一致


那么我们该如何计算重复对呢?

考虑一致点下标为i,我们需要事先处理出位置i左边比它大的数的个数w[i],比它小的数的个数l[i];右边比它大的数的个数v[i],比它小的数的个数r[i],这样所有重复对的对数为l[i]*r[i]+l[i]*v[i]+w[i]*r[i]+w[i]*v[i]

而计算这些个数可以通过树状数组求解

【时间复杂度&&优化】
O(nlogn)

题目链接→HDU 5792 World is Exploding

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 50005;
const int M = 5005;
const int inf = 1000000007;
const int mod = 1000000007;
int n,s[N],c[N],a[N];
__int64 l[N],r[N],w[N],v[N];
int lowbit(int t)
{//计算c[t]展开的项数
    return t&(-t);
}
void update(int i,int x)
{
    while(i<=n)
    {
        c[i]=c[i]+x;
        i+=lowbit(i);
    }
}
int Sum(int n) //求前n项的和.
{
    int sum=0;
    while(n>0)
    {
         sum+=c[n];
         n-=lowbit(n);
    }
    return sum;
}
int main()
{
    int i,k,Max;
    __int64 ans,sum1,sum2;
    while(~scanf("%d",&n))
    {
        sum1=sum2=0;Max=0;
        memset(c,0,sizeof(c));
        for(i=0;i=0;i--)
        {
            r[i]=Sum(s[i]-1);
            v[i]=Sum(Max)-Sum(s[i]);
            update(s[i],1);
            sum2+=r[i];
        }
        ans=sum1*sum2;
        for(i=0;i

菜鸟成长记

你可能感兴趣的:(HDU,OJ,多校练习赛,树状数组,动态规划(DP),Training,Contest)