(ICPC)亚洲区域赛(济南) L.Bit Sequence(数位dp,压缩状态)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(ICPC)亚洲区域赛(济南) L.Bit Sequence(数位dp,压缩状态)相关的知识,希望对你有一定的参考价值。

LINK

乍一看觉得非常不可做,因为似乎找不到什么比较小的状态能判断是否满足条件

如果能找到这样的状态就简单了,在递归出口写个判断函数返回即可

观察到我们需要对 i ∈ [ 0 , m ) i\\in[0,m) i[0,m)判断 f ( x + i ) = = a i f(x+i)==a_i f(x+i)==ai

x + i x+i x+i会不断进位,一旦进位就没完没了了

但是 m < = 100 m<=100 m<=100,也就是最多影响 x x x的后 7 7 7位二进制

换句话说,对于任意的 i ∈ [ 0 , m ) i\\in[0,m) i[0,m),无法就两种情况

Ⅰ.不进位

我们当前枚举的数 x x x的低 7 7 7位加上 i i i仍然小于等于 127 127 127

那么此时只需要保存 x x x 7 7 7位的状态和高于 7 7 7位的二进制 1 1 1个数即可

Ⅱ.进位

我们当前枚举的数 x x x的低 7 7 7位加上 i i i大于 127 127 127

此时会进位,但是我们惊喜的发现就算进位也只会进 1 1 1

所以只会影响到低 7 7 7位之后的连续二进制 1 1 1

那么此时只需要保存 x x x 7 7 7位的状态和高于 7 7 7位的二进制 1 1 1个数和低 7 7 7位之后的连续二进制 1 1 1个数

所以我们得到定义

f [ i ] [ j ] [ 0 / 1 ] [ 0 / 1 ] [ 0 / 1 ] f[i][j][0/1][0/1][0/1] f[i][j][0/1][0/1][0/1]表示枚举到二进制第 i i i位,当低 7 7 7位的数是 j j j,且当前已经连续了偶/奇个 1 1 1,总共有偶/奇数个 1 1 1,是否卡上界

(注:代码的状态可能和上面的定义顺序有区别)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int t,n,m,L,a[70],M[1009];
int f[129][70][2][2][2],b[2009];
//f[i][j][k][l]枚举到第i位,后六位状态为j,从第7位开始连续了奇/偶个一 
int isok(int sta,int one,int jo)
{
	for(int i=0;i<m;i++)
	{
		int x = i+sta, ans = jo;//ans表示一开始的奇偶性 
		if( x<=127 )	ans ^= ( b[x]&1 );
		else
		{
			ans = ans^( b[x-128]&1 );
			if( one==0 )	ans ^= 1;	
		}
		if( ans!=M[i] )	return 0;
	}
	return 1;
}
int dfs(int l,int sta,int one,int jo,int lim)
{
	if( f[sta][l][one][jo][lim]!=-1 )	return f[sta][l][one][jo][lim];
	if( !l )	return f[sta][l][one][jo][lim] = isok(sta,one,jo);
	int ed = lim?a[l]:1, ans = 0;
	for(int i=0;i<=ed;i++)
	{
		if( l<=7 )	ans += dfs(l-1,(sta*2+i)&127,one,jo,lim&&(i==a[l]) );
		else
		{
			if( i )
				ans += dfs(l-1,(sta*2+i)&127,one^1,jo^1,lim&&(i==a[l]) );
			else
				ans += dfs(l-1,(sta*2+i)&127,0,jo,lim&&(i==a[l]) );
		}
	}
	return f[sta][l][one][jo][lim] = ans;
}
int solve(int x)
{
	a[0] = 0;
	while( x ){ a[++a[0]]=x&1; x>>=1; }
	memset( f,-1,sizeof f );
	return dfs( a[0],0,0,0,1 );
}
signed main()
{
	for(int i=1;i<=2000;i++)	b[i] = b[i>>1]+(i&1);
	cin >> t;
	while( t-- )
	{
		cin >> m >> L;
		for(int i=0;i<m;i++)	cin >> M[i];
		cout << solve(L) << endl;
	}
}

然后开始想的是直接固定低 7 7 7位,然后 d f s dfs dfs到低 7 7 7位直接返回判断

其实也是一样的

#include<bits/stdc++.h>
using namespace std;
#define int long long
int t,n,m,L,a[70],M[1009];
int f[129][70][2][2][2],b[2009];
//f[i][j][k][l]枚举到第i位,后六位状态为j,从第7位开始连续了奇/偶个一 
int isok(int sta,int one,int jo)
{
	for(int i=0;i<m;i++)
	{
		int x = i+sta, ans = jo;//ans表示一开始的奇偶性 
		if( x<=127 )	ans ^= ( b[x]&1 );
		else
		{
			ans = ans^( b[x-128]&1 );
			if( one==0 )	ans ^= 1;	
		}
		if( ans!=M[i] )	return 0;
	}
	return 1;
}
int dfs(int l,int sta,int one,int jo,int lim)
{
	if( f[sta][l][one][jo][lim]!=-1 )	return f[sta][l][one][jo][lim];
	if( l==7 )
	{
		if( (L&127)<sta && lim )	return 0;
		else	return isok(sta,one,jo);
	}
	int ed = lim?a[l]:1, ans = 0;
	for(int i=0;i<=ed;i++)
	{
		if( i )	ans += dfs(l-1,sta,one^1,jo^1,lim&&(i==a[l]) );
		else	ans += dfs(l-1,sta,0,jo,lim&&(i==a[l]) );
	}
	return f[sta][l][one][jo][lim] = ans;
}
int solve(int x)
{
	a[0] = 0;
	while( x ){ a[++a[0]]=x&1; x>>=1; }
	int ans = 0;
	for(int i=0;i<128;i++)
	{
		memset( f[i],-1,sizeof f[i] );
		int temp = 0;
		temp  += dfs( a[0],i,0,0,1 );	
		ans += temp;
	}
	return ans;
}
signed main()
{
	for(int i=1;i<=2000;i++)	b[i] = b[i>>1]+(i&1);
	cin >> t;
	while( t-- )
	{
		cin >> m >> L;
		for(int i=0;i<m;i++)	cin >> M[i];
		if( L<=127 )
		{
			int ans = 0;
			for(int i=0;i<=L;i++)	ans += isok(i,0,0);
			cout << ans << endl;
		}
		else	cout << solve( L ) << endl;
	}
}

以上是关于(ICPC)亚洲区域赛(济南) L.Bit Sequence(数位dp,压缩状态)的主要内容,如果未能解决你的问题,请参考以下文章

第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南),签到题2题

第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南),签到题5题

第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南),签到题5题

icpc区域赛(济南)总结

icpc区域赛(济南)总结

2018 ICPC亚洲区域赛沈阳站 LTree(思维+dfs)