牛客网暑期ACM多校训练营(第一场)E.Removal(dp)

       牛客网暑期ACM多校训练营(第一场)E.Removal

传送门

昨天下午,牛客多校第一场,开局两道题,之后盯上了这题,一直挂机到比赛结束,

本蒟蒻挂机期间机队友推出了A题的规律,最后3题gg

赛后看了眼榜

葫芦爷真的

赛时想的dp[i][j]是枚举到第i个长度为j的方案数,然后就转移不出来了,emmmmm

赛后看了题解pdf,发现挂机期间队友给的思路“dp[i][j]=长度为i以数字j为结尾的方案数”是正解

扫描二维码关注公众号,回复: 2322683 查看本文章

然后这个思路被我直接否决了,对不起队友orz

按照这个思路继续下去,我们再定义ans[len]表示长度为len的方案数

每次一个循环更新ans[len]之后都要同时更新Next[len][num],因为这个时候ans[len]的数值已经变化,

而我们每次更新ans[len]都要求更新时所用的Next[len][num]为最临近一次的方案数

所以要及时更新Next[len][num]=ans[len-1]  长度为lennum结尾的方案数应该等于长度为len-1的方案数

其实就是相当于长度为len-1的串后面再加一个字符

for(int i=1; i<=n; i++)
{
       for(int j=i; j>=max(1,i-m); j--)
       {
                ans[j]=(ans[j]+ans[j-1]-Next[j][a[i]])%mod;
                Next[j][a[i]]=ans[j-1];
       }

}

由于m最大也只有10

我们暴力的去更新ans[len]的时间复杂度也只有O(nm)|n*m<=1e6

最后,就算知道正解了的我,在昨晚还是疯狂wa 50%

早上再一看代码,简直石乐志,没加mod直接取模会有负数啊..........

加了个mod再膜直接ac.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;

#define inf int(0x3f3f3f3f)
#define mod ll(1e9+7)
#define eps double(1e-7)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

int n,m,k;

int a[100005];

int Next[100005][15];

ll ans[100005];

void init()
{
    memset(Next,0,sizeof(Next));
    memset(ans,0,sizeof(ans));
    ans[0]=1;
}


int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    while(cin>>n>>m>>k)
    {
        k=n-m;
        for(int i=1; i<=n; i++)
            cin>>a[i];
        init();
        for(int i=1; i<=n; i++)
        {
            for(int j=i; j>=max(1,i-m); j--)
            {
                ans[j]=(ans[j]+ans[j-1]-Next[j][a[i]])%mod;
                Next[j][a[i]]=ans[j-1];
            }
        }
        cout<<(ans[k]+mod)%mod<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/murphyc/article/details/81127327