HDU 4455 Substrings 第37届ACM/ICPC 杭州赛区现场赛 C题 (DP)

来源:互联网 发布:致幻蘑菇 知乎 编辑:程序博客网 时间:2024/05/22 11:54

题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=4455

题目大意给你一串有序数,分成m个子集后,每个子集中不同元素的个数和是多少
这题感谢帽神的提点,不然真想不到可以这样dp
用样例为例子 1 1 2 3 4 4 5
很容易知道dp[1]=7;
当m=2时 可以分为 1 1,1 2,2 3,3 4,4 4,4 5;
这时可以发现,当m++时每个子集加入了后面一个数,最后一个子集被删去了
可以得到dp[i]=dp[i-1]-最后子集不重复元素个数+新增加的不同元素的个数。
后面两个都可以得出于是求证。
答案要用longlong。这里wa了几次~~

#include<stdio.h>#include<string.h>#define MAX 1000010int equ[MAX];   //记录距离为i的相同的数有多少个int dis[MAX];   //记录一个数离上一个相同的数的距离int a[MAX];int vis[MAX];   //记录后面哪些数出现过int f[MAX];long long ans[MAX];int main(){    int n;    while(scanf("%d",&n)==1&&n)    {        int i;        memset(dis,0,sizeof(dis));        memset(equ,0,sizeof(equ));        for(i=1;i<=n;i++)        {            scanf("%lld",&a[i]);            equ[i-dis[a[i]]]++;            dis[a[i]]=i;        }        memset(vis,0,sizeof(vis));        f[1]=1;        vis[a[n]]=1;        for(i=2;i<=n;i++)        {            if(!vis[a[n-i+1]])            {                vis[a[n-i+1]]=1;                f[i]=f[i-1]+1;            }            else            f[i]=f[i-1];        }        ans[1]=n;        long long tt=n;        for(i=2;i<=n;i++)        {            ans[i]=ans[i-1]-f[i-1];            tt-=equ[i-1];            ans[i]+=tt;        }        int m;        scanf("%d",&m);        for(i=0;i<m;i++)        {            int b;            scanf("%d",&b);        printf("%lld\n",ans[b]);    }    }}
0 0