模擬賽4 數字序列 50分做法 狀壓DP

題意:求由1到k之間的數字組成的,滿足如果ai=aj,則i-j>=ai的序列個數

一臉懵逼在比賽中想不出AC方法,50分做法:考慮狀壓,因爲新的一位能放哪些數字只和最後m-1位有關,又因爲k<=7,於是考慮狀壓.

在50分數據也就是k=5時剛好能跑出來

時間複雜度O(n*k^k),大數據直接爆炸= =畢竟太弱

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<bitset>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 10005
#define M 8
#define inf 910109
int f[2][10000];
struct S
{
	int x,y;
}s[1000];
int n,m,num=0,ma=0;
int po8[10];
int c[9];

void dfs(int k)
{
	if(k>m)
	{
		int x=0,y=0;
		fo(i,1,m)
		{
			if(i!=m)x+=c[i]*po8[i-1];
			if(i!=1)y+=c[i]*po8[i-2];
		}
//		cout<<num+1<<endl;
//		fo(i,1,m)cout<<c[i]<<' ';cout<<endl;
		s[++num].x=x;s[num].y=y;
//		f[1-m%2][x]++;
		ma=max(ma,max(x,y));
		return;
	}
	bitset<10>a;a.reset();c[k]=1;dfs(k+1);c[k]=0;
	for(int i=k-1,j=2;j<=m;i--,j++)
	{
		if(i>0)a[c[i]]=1;
		if(a[j]==0)
		{
			c[k]=j;
			dfs(k+1);
			c[k]=0;
		}
	}
}
void prework()
{
	po8[0]=1;
	fo(i,1,7)po8[i]=po8[i-1]*8;
	memset(c,0,sizeof(c));
	memset(f,0,sizeof(f));
	dfs(1);
	fo(i,1,num)f[1-m%2][s[i].x]=1;
}

int main()
{
	n=read(),m=read();
	prework();
	fo(i,m,n)
	{
		fo(j,1,num)
		{
			f[i%2][s[j].x]=0;
			f[i%2][s[j].y]=0;
		}
		fo(j,1,num)
		{
			f[i%2][s[j].y]+=f[(i+1)%2][s[j].x];
			if(f[i%2][s[j].y]>=inf)f[i%2][s[j].y]%=inf;
		}
	}
	int ans=0;
	fo(i,1,3000)
	{
		ans+=f[n%2][i];
		if(ans>=inf)ans%=inf;
	}
	
	cout<<ans<<endl;
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章