CF388D Fox and Perfect Sets

一、題目

點此看題

二、解法

我們考慮用線性基表示SS,集合SS還需要一些線性基組合出來的,但是不在線性基內的數,我們就保證線性基的最大值在nn以內。但是還要保證映射的唯一性,我們把線性基消除成上三角形式,就是如果一個基的最高位有值,那麼其他基就必須00,舉個例子(makedown\text{makedown}小技巧:二級對齊\begin{alignedat}{2}\end{alignedat}):
1xxx0xxx01xxx01\begin{alignedat}{2} 1xxx&0xxx&0\\ &1xxx&0\\ &&1 \end{alignedat} 其中xx可以隨便填,這樣就可以保證一一對應,從兩方面說明:如果基位置不同或者基個數不同,那麼集合肯定不同,如果xx不同那麼集合也不同。這樣就說明了是唯一映射。

那麼問題變成了求滿足上述條件的線性基個數,可以考慮二進制位dpdp,設dp[i][j][k]dp[i][j][k]表示從高到低位,現在到了ii這一位,jj爲基的個數,kk表示maxmax是否頂到上界,滿足條件的線性基個數,來討論一波轉移。

Case one:k=0
  • 不新加入基,而是修改xx(含義見上圖),然後我們隨便怎麼填都能滿足條件,因爲當前的kk已經爲00了,轉移:dp[i1][j][0]=dp[i][j][0]×2jdp[i-1][j][0]=dp[i][j][0]\times 2^j
  • 新加入基,轉移:dp[i1][j+1][0]=dp[i][j][0]dp[i-1][j+1][0]=dp[i][j][0]
Case two:k=1

如果nni1i-1上有值的話:

  • 使最大值i1i-1位爲00,那麼:dp[i1][j][0]=x×dp[i][j][1]dp[i-1][j][0]=x\times dp[i][j][1],其中xxi1i-1位爲00的方案數(如果j=0j=0那麼x=1x=1,否則x=2j1x=2^{j-1}
  • 使最大值i1i-1位爲11,那麼:dp[i1][j][1]=y×dp[i][j][1]dp[i-1][j][1]=y\times dp[i][j][1],其中yyi1i-1位爲11的方案數(如果j=0j=0那麼y=0y=0,否則y=2j1y=2^{j-1}
  • 加入一個基:dp[i1][j+1][1]=dp[i][j][1]dp[i-1][j+1][1]=dp[i][j][1]

otherwiseotherwise,只能讓當前位爲00dp[i1][j][1]=x×dp[i][j][1]dp[i-1][j][1]=x\times dp[i][j][1]

#include <cstdio>
#define int long long
const int jzm = 1e9+7;
int read()
{	
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n,ans,dp[35][35][2];
int add(int &a,int b)
{
	a=(a+b)%jzm;
}
signed main()
{
	n=read();
	dp[30][0][1]=1;
	for(int i=30;i>0;i--)
		for(int j=0;j<=30;j++)
		{
			add(dp[i-1][j][0],(1<<j)*dp[i][j][0]%jzm);
			add(dp[i-1][j+1][0],dp[i][j][0]);
			int x=j?(1<<j-1):1,y=j?(1<<j-1):0;
			if(n>>(i-1)&1)
			{
				add(dp[i-1][j][0],x*dp[i][j][1]%jzm);
				add(dp[i-1][j][1],y*dp[i][j][1]%jzm);
				add(dp[i-1][j+1][1],dp[i][j][1]);
			}
			else add(dp[i-1][j][1],x*dp[i][j][1]%jzm);
		}
	for(int i=0;i<=30;i++)
		add(ans,dp[0][i][0]),add(ans,dp[0][i][1]);
	printf("%lld\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章