2019牛客暑期多校训练1

Equivalent Prefixes

这个是一个用单调栈的题目,至于为什么可以用单调栈?

把两个数组同时跑单调栈,如果每次进栈最多一个,当然在这个进栈之前肯定会有数出栈,

如果存在一个数进栈了,然后这个时候判断一下进栈的这个数的位置是不是相同,如果不相同就说明肯定是不对的。

为什么说这个时候只要考虑这个栈内的位置呢?

首先,这个最小值之前的数肯定是不要考虑的,因为当前的栈底就是目前位置最小的了,之后的数和之前的数RMQ函数返回的函数值肯定是这个栈底。

然后就是考虑栈内元素,这个应该很好想了。

#include <cstdio>//描述中的“如果找到,就说“X,let’s fly”(此处,X为开始时间)…"
#include <cstdlib>//和Output中的 “X, let's fly”
#include <cstring>//里的“ ’ ”和 “ ' ” 不是一个符号,别复制错了!!!
#include <queue>
#include <vector>
#include <algorithm>
#include <string>
#include <stack>
#include <iostream>
#include <map>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
int queue_mina[maxn];
int queue_minb[maxn];
int a[maxn], b[maxn];

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        bool flag = 1;
        int ans = n;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
        int f1 = 1, t1 = 0;
        int f2 = 1, t2 = 0;
        int r = 1;
        while(r<=n)
        {
            while (f1 <= t1 && a[r] < a[queue_mina[t1]]) t1--;
            queue_mina[++t1] = r;
            while (f2 <= t2 && b[r] < b[queue_minb[t2]]) t2--;
            queue_minb[++t2] = r;
            //printf("t1=%d t2=%d queue_mina[%d]=%d queue_minb[%d]=%d
", t1, t2, t1, queue_mina[t1], t2, queue_minb[t2]);
            if (t1 != t2)
            {
                flag = 0;
                ans = r - 1;
                break;
            }
            r++;
        }
        printf("%d
", ans);
    }
    return 0;
}
A

 ABBA

这个题目是一个dp,现在看完题解之后感觉还比较好想,但是这个条件的判断我觉得还是比较难的。

就是判断哪一种一定不是答案

下面有两种写法,理解了任意一种另一种都可以很快的写出来

    if(i-j>n||j-i>m)//为什么这么写就是对的呢?
                    //因为i代表的是A的数量,j代表的是B的数量,如果A-B的数量大于n,就说明前面至少有n+1个A,这个B的数肯定
                    //有一部分在后面,所以这样的话AB的数量肯定>n,这样就不对了,后面的j-i>m 同理可得。
                    //这里可以筛出一部分肯定不对的,那么为什么满足这个就肯定是正确的呢。
                    //这个可以这么理解,这个if条件句把一定不对的筛出去了,如果后面有不合理的状态放到了dp数组里面
                    //最后一直往后走放A,B前面不合理的状态还是会被筛出去的
                {
                    dp[i][j] = 0;
                    continue;
                }

这个是一种dp转移 dp[x][y]表示选了x个A,y个B的方案数

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
const int mod = 1e9 + 7;
ll dp[4400][4400];

int main()
{
    int n, m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<=n+m;i++)
        {
            for(int j=0;j<=n+m;j++)
            {
                dp[i][j] = 0;
            }
        }
        for(int i=0;i<=(n+m);i++)
        {
            for(int j=0;j<=(n+m);j++)
            {
                if(i-j>n||j-i>m)//为什么这么写就是对的呢?
                    //因为i代表的是A的数量,j代表的是B的数量,如果A-B的数量大于n,就说明前面至少有n+1个A,这个B的数肯定
                    //有一部分在后面,所以这样的话AB的数量肯定>n,这样就不对了,后面的j-i>m 同理可得。
                    //这里可以筛出一部分肯定不对的,那么为什么满足这个就肯定是正确的呢。
                    //这个可以这么理解,这个if条件句把一定不对的筛出去了,如果后面有不合理的状态放到了dp数组里面
                    //最后一直往后走放A,B前面不合理的状态还是会被筛出去的
                {
                    dp[i][j] = 0;
                    continue;
                }
                if (i == 0 || j == 0) dp[i][j] = 1;
                else dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod;
            }
        }
        printf("%lld
", dp[n + m][n + m]);
    }
    return 0;
}
1

这个是dp[x][y]表示前面x个位置选了y个B的方案数

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
const int mod = 1e9 + 7;
ll dp[4400][4400];
 
int main()
{
    int n, m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<=2*(n+m);i++)
        {
            for(int j=0;j<=2*(n+m);j++)
            {
                dp[i][j] = 0;
            }
        }
        dp[0][0] = 1;
        if (n != 0) dp[1][1] = 1;
        if (m != 0) dp[1][0] = 1;
        for(int i=1;i<=2*(n+m);i++)
        {
            for(int j=0;j<=i;j++)
            {
                if(i-2*j>m||2*j-i>n)
                {
                    dp[i][j] = 0;
                    continue;
                }
                if (j == 0) dp[i][j] = 1;
                else dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % mod;
            }
        }
        printf("%lld
", dp[2 * (n + m)][n + m]%mod);
    }
    return 0;
}
2
原文地址:https://www.cnblogs.com/EchoZQN/p/11246775.html