CSP-S模拟29 2025.10.11

rt:
image

A. 一个赢家

题面link

正在施工中...

B. 排列计数

题面link

薛定谔の赛时

这题是第三次被换上来的,前两个题都有原题(but我太蒻没写过)
rt:
image

赛时 觉得它没T4可做 就直接打的T4(结果T4调好久...事实证明我糖了QAQ)
所以没有赛时。。。

正解

神秘组合数+神秘DP
反正就是十分神秘
以下思路来自机房大蛇SKK
好像是听懂了嘻嘻嘻

—————————————我是一条分隔线——————————————

题意转化

首先将题目和数据进行转化

考虑对\(x_i\)进行分解质因数,发现若它的一个质因子出现了偶数次(即其有一个因数为完全平方数),则这个质因子不能对答案判断产生贡献。
以下是解释:
让我们来手玩两个数3250
发现它们的乘积1600显然是一个完全平方数。
考虑如上进行拆分32/16=2,50/25=2,其剩余的质因子是相等的,所以它们两个的乘积就是完全平方数。

原因

点击查看证明

显然易得

\(a=p_1^2*p_2^2*p_3^3*p_4^3\)

\(b=p_3^3*p_4*p_5^2*p_6^2\)

\(a*b=p_1^2*p_2^2*p_3^6*p_4^4*p_5^2*p_6^2\)是完全平方数

\(sqrt(a*b)=p_1*p_2*p_3^3*p_4^2*p_5*p_6\)

分解后的\(a'=p_3*p_4\) \(b'=p_3*p_4\)

\(a'*b'=p_3^2*p_4^2\)是完全平方数

\(sqrt(a'*b')=p_3*p_4\)

余下的推广即可

所以就可以把题转换为:

对一个序列,让其相等的元素均不相邻,方案数有多少。

DP

接下来考虑DP:

定义

定义\(dp[i][j]\)为对于前\(i\)种元素组成的序列来说,其中有\(j\)对相邻数的乘积为完全平方数的方案数。

发现最终答案是\(dp[种类数][0]*各种元素的数量的阶乘\)

状态转移

考虑如何状态转移
我们钦定\(res\)为第\(i\)种元素的个数,发现可以将它中的元素分为两部分

  1. 单独拿出的\(x\)个元素(将其插入与其相同的元素旁边则直接令此次转移的积为完全平方数的数对个数加\(x\),即\(dp\)数组的第二维+\(x\))
  2. 插入之前的序列的\(y\)个元素(使前\(i\)个元素序列里的\(j\)对积为完全平方数的个数减小或不变)

rt:
增加的情况

image

减少的情况

image

不变的情况
image

所以我们又可以将\(y\)分成\(p\),\(q\)两部分,\(p\)为使其个数减少的部分,\(q\)为使其个数不变的部分。

DP转移方程

\[dp[i+1][j-p+x]+=dp[i][j]*C(res-1,y-1)*C(j,p)*C(sum+1-j,q); \]

此时\(sum\)为前\(i\)中元素的总个数,C为组合数。

代码

#include<bits/stdc++.h>
using namespace std;
long long C[610][610],jc[610];
long long sum,n,a[610];
long long dp[610][610]; 
map<long long,long long> js;//<元素种类(剩余因数),个数> 
const long long mod=1e9+7;
long long hf(long long x)//将x中质因子个数为偶数个的质因子扔掉 
{
	for(long long i=2;i*i<=x;i++)
	{
		long long pf=i*i;
		while(x%pf==0)
		{
			x/=pf;
	    }
	}
	return x;
}
int main()
{
	freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
	ios::sync_with_stdio(false);
	for(long long i=0;i<=600;i++)//杨辉三角形计算组合数 
	{
		C[i][0]=C[i][i]=1;
		for(long long j=1;j<=i;j++)
		{
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
		}
	}
	jc[0]=1;
	for(long long i=1;i<=600;i++)//阶乘 
	{
		jc[i]=jc[i-1]*i%mod;
	}
	long long T;
	cin>>T;
	while(T--)
	{
		cin>>n;
		for(long long i=1;i<=n;i++)
		{
			cin>>a[i];
		}
	    memset(dp,0,sizeof(dp));
	    sum=0;//前i种元素的总个数 
	    js.clear();
	    for(long long i=1;i<=n;i++)
	    {
	    	a[i]=hf(a[i]);
	    	js[a[i]]++;
		}
	    long long i=0;
	    dp[1][0]=1;
	    for(auto cnt:js)
	    {
	    	i++;
	    	long long res=cnt.second;
	    	for(long long j=0;j<=sum;j++)
	    	{
	    		if(!dp[i][j])
	    		{
	    			continue;
				}
				for(long long x=0;x<=res-1;x++)
				{
					long long y=res-x;
					for(long long p=0;p<=min(y,j);p++)
					{
						long long q=y-p;
						dp[i+1][j-p+x]=(dp[i+1][j-p+x]+dp[i][j]*C[res-1][y-1]%mod*C[j][p]%mod*C[sum+1-j][q]%mod)%mod;
					}
				}
			}
			sum+=res; 
		}
		long long ans=dp[i+1][0];
		for(auto cnt:js)
		{
			ans=ans*jc[cnt.second]%mod;//乘相同元素的个数 
		}
		cout<<ans<<endl;
	} 
	return 0;
}
//别忘开 long long 且及时取模 

C. 树上染黑

题面link

正在施工中...

D. 摆放花盆

题面link

正在施工中...

posted @ 2025-10-11 20:03  BIxuan—玉寻  阅读(44)  评论(8)    收藏  举报