2018牛客暑假多校(第一场)

E-Remove

d p [ i ] [ j ] 表示前 i 个数,删除 j 个的方案数
假如每个数字都是不重复的,那么很简单, d p [ i ] [ j ] = d p [ i 1 ] [ j ] + d p [ i 1 ] [ j 1 ] ,并且还阔以直接用组合数算出来,就是 d p [ i ] [ j ] = C i j
但是现在有重复的了,通过第一个样例就可以看出来
我们写一个一般一点的数列
1 2 3 4 9 5 6 7 9
9 个数里面删除 6 个数,问答案有多少种?

这个的答案是 78 ,我们来看这个 78 是怎么来的:
假如不考虑重复的情况,答案就是 C 9 6 = 84 ,然后要删除重复的
重复的就是以下情况:
这里写图片描述

删除圆圈里的这 4 个数,数列都变成了 1 2 3 4 9 ,而这种情况只删除了 4 个数,还要再在前面 1 2 3 4 中删除 2 个数,就是 C 4 2 = 4

所以总的答案就是 C 9 6 C 4 2 = 84 6 = 78
也想当于 d p [ 9 ] [ 6 ] d p [ 4 ] [ 2 ] = 78
这样就把重复的减去了

只要满足这种重复的条件,减去就行了

#include"bits/stdc++.h"
#define out(x) cout<<#x<<"="<<x
#define outdp(x,y) cout<<"dp["<<(x)<<"]["<<(y)<<"]="<<dp[(x)][(y)]
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int MOD=1e9+7;
LL dp[maxn][11];
int last[11];//¼Ç¼Õâ¸öÊýÉÏÒ»´Î³öÏÖµÄλÖà 
int main()
{
    int N,M,K;
    while(cin>>N>>M>>K)
    {

        memset(last,0,sizeof(last));
        memset(dp,0,sizeof(dp));
        for(int i=0;i<=N;i++)dp[i][0]=1;//Ò»¸ö¶¼²»É¾ÓÐÒ»ÖÖÇé¿ö
        for(int i=1;i<=N;i++)
        {
            int t;
            scanf("%d",&t);
            for(int j=1;j<=M&&j<=i;j++)
            {
                dp[i][j]+=dp[i-1][j]+dp[i-1][j-1];
                if(last[t])//Èç¹û³öÏÖͬÑùµÄ£¬¾ÍҪɾȥ 
                {
                    int len=i-last[t];//Á½¸öͬÑùµÄÊýÖÐҪɾ³ýµÄ¸öÊý 
                    if(j>=len)dp[i][j]-=dp[i-len-1][j-len];
                }
                if(dp[i][j]>MOD||dp[i][j]<0)dp[i][j]=(dp[i][j]%MOD+MOD)%MOD;
            }
            last[t]=i;
        }
        cout<<dp[N][M]<<endl;
    }
}

J-Different Integers

题意:求区间中不同值的个数

这道题的思路是这样的:
从左到右,每个数只在他最后出现的地方标记一下,如果新出现了这个数,那么就是这个数加 1 ,那么这个数在上一个位置就减 1 成为 0 ,就像这样:
这里写图片描述
每次的询问 L , R ,只要有这样的一张表就好得到答案

所以用树状数组啥的维护一哈就行了

#include"bits/stdc++.h"
using namespace std;
typedef  long long LL;
const LL maxn=2e5+5;
LL a[maxn],tree[maxn],Ans[maxn];
LL N,Q;
struct AAA
{
    LL L,R,id;
    bool operator<(const AAA &a)const
    {
        return R<a.R;
    }
};
AAA qry[maxn];
void Add(int pos,int v)
{
    for(int i=pos; i<=2*N; i+=(i&-i))
    {
        tree[i]+=v;
    }
}
LL getsum(int pos)
{
    LL res=0;
    for(int i=pos; i>=1; i-=(i&-i))
    {
        res+=tree[i];
    }
    return res;
}
LL vis[maxn];
int main()
{
    while(scanf("%d%d",&N,&Q)!=EOF)
    {
        memset(tree,0,sizeof(tree));
        for(int i=1; i<=N; i++)scanf("%d",&a[i]),a[i+N]=a[i];
        for(int i=1; i<=Q; i++)
        {
            int L,R;
            scanf("%d%d",&qry[i].R,&qry[i].L);
            qry[i].R+=N;
            qry[i].id=i;
            if(qry[i].L>qry[i].R)swap(qry[i].L,qry[i].R);
        }
        sort(qry+1,qry+1+Q);
        N<<=1;
        memset(vis,0,sizeof(vis));
        int now=0;
        for(int i=1;i<=Q;i++)
        {
            int L=qry[i].L,R=qry[i].R;
            for(;now<R;)
            {
                now++;
                if(vis[a[now]]==0)
                {
                    vis[a[now]]=now;
                    Add(now,1);
                }
                else
                {
                    Add(vis[a[now]],-1);
                    vis[a[now]]=now;
                    Add(now,1);
                }
            }
            Ans[qry[i].id]=getsum(R)-getsum(L-1);
        }
        for(int i=1; i<=Q; i++)printf("%d\n",Ans[i]);
    }
}

猜你喜欢

转载自blog.csdn.net/swustlpf/article/details/81168657
今日推荐