牛客IOI周赛27-提高组 C.马老师(容斥dp)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客IOI周赛27-提高组 C.马老师(容斥dp)相关的知识,希望对你有一定的参考价值。

LINK

如果在第 i i i个位置出现了第 j j j位二进制 1 1 1,那么 [ i , n ] [i,n] [i,n]都有第 j j j位二进制 1 1 1

于是定义 f [ i ] [ j ] f[i][j] f[i][j]表示当前考虑前 i i i位二进制,数列和为 j j j的方案数

f [ i ] [ j ] + = ∑ r = 1 n f [ i − 1 ] [ j − r ∗ ( 1 < < i ) ] f[i][j]+=\\sum\\limits_{r=1}^{n}f[i-1][j-r*(1<<i)] f[i][j]+=r=1nf[i1][jr(1<<i)]

暴力转移复杂度当然还是很高,注意到

f [ i ] [ j ] f[i][j] f[i][j] f [ i ] [ j − ( 1 < < i ) ] f[i][j-(1<<i)] f[i][j(1<<i)]的转移方程式非常相似,所以我们直接先令

Ⅰ. f [ i ] [ j ] = f [ i ] [ j − ( 1 < < i ) ] f[i][j]=f[i][j-(1<<i)] f[i][j]=f[i][j(1<<i)]

然后考虑 j j j还可以从上一轮的 j − ( 1 < < i ) j-(1<<i) j(1<<i)状态转移而来,所以

Ⅱ. f [ i ] [ j ] + = f [ i − 1 ] [ j − ( 1 < < i ) ] f[i][j]+=f[i-1][j-(1<<i)] f[i][j]+=f[i1][j(1<<i)]

特别的,如果 j > = ( n + 1 ) ∗ ( 1 < < i ) j>=(n+1)*(1<<i) j>=(n+1)(1<<i),那么其实是算多了的

因为最多从 j − n ∗ ( 1 < < i ) j-n*(1<<i) jn(1<<i)处转移而来,所以此时减去算多的部分,也就是

Ⅲ. f [ i ] [ j ] − = f [ i − 1 ] [ j − ( n + 1 ) ∗ ( 1 < < i ) ] f[i][j]-=f[i-1][j-(n+1)*(1<<i)] f[i][j]=f[i1][j(n+1)(1<<i)]

最后,不要忘记继承上一轮的状态,因为可以不选这个二进制

Ⅳ. f [ i ] [ j ] + = f [ i − 1 ] [ j ] f[i][j]+=f[i-1][j] f[i][j]+=f[i1][j]

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
using in = long long;
const int maxn = 5e6+10;
int n,m,f[2][maxn];
void upd(int &x,int y){ x = (x+y)%mod; }
signed main()
{
	cin >> n >> m;
	for(int i=0;i<=m && i<=n;i++)	f[0][i] = 1;
	for(int i=1;i<=23;i++)//考虑每个二进制放的位置
	{
		int t = i&1, v = t^1;
		long long lim = (n+1)*(1ll<<i);
		for(int j=0;j<=m;j++)
		{
			f[t][j] = 0;
			if( j>=(1ll<<i) )
			{
				upd( f[t][j],f[t][j-(1ll<<i)] );
				upd( f[t][j],f[v][j-(1ll<<i)] );
			}
			if( j>=lim )
				upd( f[t][j],-f[v][j-lim] );	
		}
		for(int j=0;j<=m;j++)	upd( f[t][j],f[v][j] );
	}
	cout << ( f[23&1][m]%mod+mod )%mod; 
}

以上是关于牛客IOI周赛27-提高组 C.马老师(容斥dp)的主要内容,如果未能解决你的问题,请参考以下文章

牛客IOI周赛27-普及组 D 旅游(简单floyd)

牛客IOI周赛26-普及组A-平行四边形霖行

牛客IOI周赛26-普及组 最短路

牛客IOI周赛26-普及组 B. 子序列(int128)

牛客IOI周赛21-普及组 D.瞎位移群岛(bfs)

牛客练习赛84 C.牛客推荐系统开发之选飞行棋子(状态dp)