luogu P2267 琪琪的项链

---恢复内容开始---

神仙题。。。

第一眼还以为是道数学题。。。

看了题解发现是道恶心的Dp。。

设 f[i] 表示 以珠子 i 为结尾的方案数(必须选i),然后能对其做出贡献的只有  x ~ i-1 这段区间。。

x表示 a [ x ] == a [ i ] && a[ x+1 ~  i-1 ] != a [ i ] 也就是最后一个和 i 颜色相同的位置。。

为什么??

因为在1~x-1中选出若干个后,再选 x 或 i 的话就重复了。。

所以转移方程就是

f[i]=(sigma)(j=x,j<=i-1)f[j] (a[x]==a[i] ,a[x+1  ~  i - 1]!=a[i] )

额就是这样子。。

对于我这种蒟蒻太难了 。。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 500010
using namespace std;
int n,m,last[N],tmp[N];
ll a[N],b[N],sum[N];
inline ll read(){
	char c=getchar();ll x=0,flag=1;
	while(c<'0' || c>'9'){if(c=='-') flag=-1;c=getchar();}
	while(c>='0' && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
	return x*flag;
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i];
	sort(b+1,b+n+1);int cnt=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
	for(int i=1;i<=n;i++){last[i]=tmp[a[i]];tmp[a[i]]=i;}
	for(int i=1;i<=n;i++){
		if(last[i]) sum[i]=(2*sum[i-1]%m-sum[last[i]-1])%m;
		else sum[i]=(sum[i-1]+sum[i-1]+1)%m;
	} 
	printf("%lld\n",(sum[n]%m+m)%m);return 0;
}

  

 

posted @ 2019-11-04 10:09  dzzx_Syh  阅读(142)  评论(0编辑  收藏  举报