2019牛客国庆集训派对day1 D.Modulo Nine(巧妙的dp)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019牛客国庆集训派对day1 D.Modulo Nine(巧妙的dp)相关的知识,希望对你有一定的参考价值。

LINK

考虑这么多限制很不好做,而且区间可能彼此嵌套,无法同时满足限制

考虑一段区间乘机模 9 9 9为零有什么特殊点.

其实就是分解质因子之后,至少有两个因子都为 3 3 3

那么我们在第 i i i位填充了 3 , 6 3,6 3,6后,相当于在这个位置设置了一个因子 3 3 3

我们在第 i i i位填充了 9 , 0 9,0 9,0后,相当于在这个位置设置了两个因子 3 3 3

所以我们对于每个位置 i i i,考虑它作为限制区间的右端点,那么若干个左端点只有最右的区间有用

所以我们定义 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示填充了 [ 1 , i ] [1,i] [1,i]的数字,且满足了所有右端点小于等于 i i i的区间限制

最近出现的因子 3 3 3 k k k位置,次近的是 j j j位置

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7;
const int maxn = 59;
typedef pair<int,int>p;
int n,m,f[maxn][maxn][maxn],lim[maxn];
signed main()
{
	while( cin >> n >> m )
	{
		for(int i=1;i<=m;i++)
		{
			int l,r; cin >> l >> r;
			if( lim[r]==0 || lim[r]<l )	lim[r] = l;
		}
		
		f[0][0][0] = 1;
		for(int i=0;i<n;i++)
		for(int j=0;j<=i;j++)
		for(int k=j;k<=i;k++)
		{
			if( j<lim[i] )	continue;
			f[i+1][i+1][i+1] = ( f[i+1][i+1][i+1]+2*f[i][j][k] )%mod;//这个位置放数字9,0
			f[i+1][k][i+1] = ( f[i+1][k][i+1] + 2*f[i][j][k] )%mod;//这个位置放数字3,6 
			f[i+1][j][k] = ( f[i+1][j][k] + 6*f[i][j][k] )%mod;//放其他数字 
		}
		int ans = 0;
		for(int j=0;j<=n;j++)
		for(int k=j;k<=n;k++)
			if( j>=lim[n] )	ans = ( ans+f[n][j][k] )%mod;
		for(int i=0;i<=n;i++)
		for(int j=0;j<=n;j++)
		for(int k=0;k<=n;k++)
			f[i][j][k] = 0;
		memset( lim,0,sizeof lim );
		cout << ans << endl;
	}
}

以上是关于2019牛客国庆集训派对day1 D.Modulo Nine(巧妙的dp)的主要内容,如果未能解决你的问题,请参考以下文章

2019牛客国庆集训派对day1 D.Modulo Nine(巧妙的dp)

2019牛客国庆集训派对day3 排列(状压dp)

2019牛客国庆集训派对day3 时间旅行(思维)

2019牛客国庆集训派对day3 J.买一送一(dfs+组合数学)

2019牛客国庆集训派对day2 C.Just h-index(主席树)

2019牛客国庆集训派对day2 J.Vertex Cover(思维,组合数学算贡献)