【CF840C】On the Bench DP

【CF840C】On the Bench

题意:给你一个长度为n的数组{ai},定义一个1到n的排列是合法的,当且仅当对于$1\le i <n$,$a_i\times a_{i+1}$不是完全平方数。求所有合法的排列个数。

$n\le 300,a_i\le 10^9$

题解:显然我们先把ai中的平方因子除掉,然后就变成了任意相邻两数不能相同的排列数。显然要将相同的数放到一起处理。

考虑DP,令f[i][j][k]表示枚举到第i个数,一共有j个相邻的位置是相同的,在之前所有和ai相同的数中,有k个相邻的位置 的方案数。转移复杂度$O(n^3)$。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll P=1000000007;
int n;
int v[310];
ll f[2][310][310];
inline void upd(ll &x,const ll &y) {x+=y;	if(x>=P)	x%=P;}
int main()
{
	scanf("%d",&n);
	int i,j,k,d=0,tmp=0,t;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&t),v[i]=1;
		for(j=2;j*j<=t;j++)	if(t%j==0)
		{
			tmp=0;
			while(t%j==0)	tmp^=1,t/=j;
			if(tmp)	v[i]*=j;
		}
		if(t>1)	v[i]*=t;
	}
	sort(v+1,v+n+1);
	f[0][0][0]=1;
	for(i=1;i<=n;i++)
	{
		if(v[i]>v[i-1])
		{
			for(j=0;j<=i;j++)	for(k=1;k<=tmp;k++)	upd(f[d][j][0],f[d][j][k]),f[d][j][k]=0;
			tmp=0;
		}
		d^=1,memset(f[d],0,sizeof(f[d]));
		for(j=0;j<=i;j++)	for(k=0;k<=tmp&&k<=j;k++)
		{
			upd(f[d][j+1][k+1],f[d^1][j][k]*(2*tmp-k));
			if(j)	upd(f[d][j-1][k],f[d^1][j][k]*(j-k));
			upd(f[d][j][k],f[d^1][j][k]*(i-(2*tmp-k)-(j-k)));
		}
		tmp++;
	}
	printf("%lld",f[d][0][0]);
	return 0;
}
posted @ 2018-01-24 14:11  CQzhangyu  阅读(552)  评论(0编辑  收藏  举报