(ICPC)亚洲区域赛(济南) L.Bit Sequence(数位dp,压缩状态)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(ICPC)亚洲区域赛(济南) L.Bit Sequence(数位dp,压缩状态)相关的知识,希望对你有一定的参考价值。
乍一看觉得非常不可做,因为似乎找不到什么比较小的状态能判断是否满足条件
如果能找到这样的状态就简单了,在递归出口写个判断函数返回即可
观察到我们需要对 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题