[冲刺国赛2022] 模拟赛5

题目描述

对于一个长度为 \(n\) 的排列 \(p\),如果 \(p_i=2p_{i+1},p_{i+1}=2p_i\),那么 \(a_i=1\);否则 \(a_i=0\)

现在给定 \(a\) 数组,问有多少个排列可以生成这样的 \(a\)

\(n\leq 40\)

解法

考虑把 \(n\) 个数划分为若干个二倍链(比如 \(1,2,4,8,16,32\)),然后把链的其中一段拆出来放到原序列中,就可以产生 \(a\) 序列中连续的一段 \(1\)

我们按顺序扫描 \(a\) 数组 \(dp\),因为相同长度的链是等价类,所以我们只需要记录所有长度对应链的数量,状态数非常少。此外我们还要记录上一个填入的数,导致分裂出了两条链 \(x,y\) 。假设现在考虑到了位置 \(p\),转移:

  • 如果 \(a_p=0\),那么枚举填入哪个数,注意这个数不能是 \(x\) 的尾部 或者 \(y\) 的头部,要不然会产生 \(1\);然后把这个数的链分裂开来,更改链长分布的同时记录新的 \(x',y'\)
  • 如果 \(a_p=1\),因为要和上一个位置形成二倍关系,所以只能用 \(x,y\),那么讨论一下用哪一个即可。

还是需要把状态哈希之后存进 \(\tt map\) 中,要用的时候再重新解密,时间充裕,怎么写都可以。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
const int M = 45;
const int MOD = 1e9+7;
#define ll long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,a[M];map<ll,int> dp;
struct node
{
	int b[7],x,y;
	node() {x=y=0;memset(b,0,sizeof b);}
}z;
void add(int &x,int y) {x=(x+y)%MOD;}
ll encode(node s)
{
	ll r=0;
	for(int i=6;i>=1;i--) r=r*41+s.b[i];
	r=r*7+s.x;r=r*7+s.y;
	return r;
}
node decode(ll r)
{
	node s;
	s.y=r%7;r/=7;
	s.x=r%7;r/=7;
	for(int i=1;i<=6;i++) s.b[i]=r%41,r/=41;
	return s;
}
signed main()
{
	freopen("book.in","r",stdin);
	freopen("book.out","w",stdout);
	n=read();
	for(int i=1;i<n;i++)
		scanf("%1d",&a[i]);
	for(int i=1;i<=n;i++) if(i&1)
	{
		int l=0;
		for(int j=i;j<=n;j<<=1) l++;
		z.b[l]++;
	}
	for(int i=1;i<=n;i++) if(i&1)
	{
		int l=0;
		for(int j=i;j<=n;j<<=1) l++;
		for(int j=1;j<=l;j++)
		{
			int x=j-1,y=l-j;node t=z;
			t.b[l]--;t.b[x]++;t.b[y]++;
			t.x=x;t.y=y;
			dp[encode(t)]++;
		}
	}
	while(!dp.empty())
	{
		ll h=dp.rbegin()->first;
		int c=dp.rbegin()->second;
		dp.erase(--dp.end());
		if(!h) {printf("%d\n",c);return 0;}
		node s=decode(h);int l=n,r=0;
		for(int i=1;i<=6;i++) l-=s.b[i]*i;
		if(a[l]==0)
		{
			for(int i=1;i<=6;i++) if(s.b[i])
				for(int j=1;j<=i;j++)
				{
					int w=s.b[i]-(s.x==i)-(s.y==i);
					node t=s;t.b[i]--;
					t.b[t.x=j-1]++;t.b[t.y=i-j]++;
					add(dp[encode(t)],1ll*c*(w+
					(s.x==i&&j<i)+(s.y==i&&j>1))%MOD);
				}
		}
		else
		{
			r=l;while(a[r]==a[l]) r++;l=r-l;
			if(s.x>=l)
			{
				node t=s;t.b[t.x]--;
				t.x-=l;t.y=0;t.b[t.x]++;
				add(dp[encode(t)],c);
			}
			if(s.y>=l)
			{
				node t=s;t.b[t.y]--;
				t.y-=l;t.x=0;t.b[t.y]++;
				add(dp[encode(t)],c);
			}
		}
	}
	puts("0");return 0;
}
posted @ 2022-06-04 19:16  C202044zxy  阅读(78)  评论(0编辑  收藏  举报