ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「AGC036F」Square Constraints 题解

2022-08-24 19:31:28  阅读:234  来源: 互联网

标签:方案 Square 题解 ll 容斥 le ans 2n Constraints


「AGC036F」Square Constraints 题解

题目大意

给定一个整数 $ n $,求有多少种 $ 0\ -\ 2n!-!1 $ 的排列 $ P $,使得对于每个 $ i $,都有 $ n^2 \le i^2 + P_i^2 \le 4n^2 $。输出答案对给定的 $ m $ 取余的结果

输入

两个整数,$ n \(,\) m $。

输出

一个整数,表示答案。


思路

初始想法

通过 $ n^2 \le i^2 + P_i^2 \le 4n^2 $ 这个式子,我们很容易想到用 $ i^2 + P_i^2 \le 4n^2 $ 的方案数减去 $ i^2 + P_i^2 < n^2 $ 的方案数。但是我们发现实际上不可做。不过这种想法提示我们可以考虑容斥

深入思考

首先,我们提炼一下问题模型:

  • 对于一个 $ 0\ -\ 2n-1 $ 组成的序列 $ P $,限制 $ a_i \le P_i \le b_i $,求方案数。

我们考虑这个问题的弱化版:

  • 对于一个 $ 0\ -\ 2n-1 $ 组成的序列 $ P $,限制 $ P_i \le a_i $,求方案数。

我们考虑将 $ a $ 数组从小到大排序,那么这个弱化版的答案为:

\[\underset{i=0}{\overset{2n-1}{\prod}}a_i-i \]

证明:

首先将 $ a $ 数组从小到大排序。

对于这个排列 $ P $,我们肯定先从 $ a $ 小的开始放。所以第一步的方案数为 $ a_0 $ 。

再考虑下一个数 $ 1 $。此时剩下 $ 2n-1 $ 个数。因为 $ a $ 从小到大,所以上一轮选走的数一定小于等于 $ a_1 $。此时的方案数为 $ a_1-1 $。

因为这些步骤是递进的,所以方案数是每一步的方案数的乘积。最终方案数即为:

\[a_0 \times (a_1-1) \times (a_2-2) \times \dots \times (a_{2n-1}-2n+1)\\ =\underset{i=0}{\overset{2n-1}{\prod}}a_i-i \]

证毕。

而原问题模型多了一个限制条件,不难想到将满足两个条件的最大值都设出来,综合在一起,套用公式得到答案


回到本题,我们将满足条件的最大值设出来。

我们尝试设 $ F(i) $ 为满足 $ i^2 + P_i^2 \le 4n^2 $ 的 $ P_i $ 的最大值, $ G(i) $ 为满足 $ i^2 + P_i^2 < n^2 $ 的 $ P_i $ 的最大值。其中 $ i \in [0,2n-1] $。

通过观察我们不难发现:

  1. $ F $ 和 $ G $ 两个函数值随着 $ i $ 的增大而减小。

    $ n^2 $ 和 $ i^2 $ 为定值,$ i $ 增大,则 $ i^2 $ 增大,那么 $ P_i^2 $ 就会减小。

  2. $ G(i) $ 满足 $ i \in [0,n-1] $。

    当 $ i \ge n $ 时,$ i^2 \ge n^2 $,要使 $ i^2 + P_i^2 < n^2 $,则 $ P_i^2 < 0 $,无解。

  3. $ \max_{i=0}^{n-1}(G_i) < \min_{i=0}^{n-1}(F_i) $。

    由于第一条规律:$ \max_{i=0}^{n-1}(G_i) $ 即 $ G_0 \(,\) \min_{i=0}^{n-1}(F_i) $ 即 $ F_{n-1} $,

    $ \because 0^2 + G_0^2 < n^2 , n^2 + F_{n-1}^2 \le 4n^2 $

    $ \therefore G_0^2 < n^2 , F_{n-1}^2 \le 3n^2 $

    $ \because n^2 \le 3n^2 $

    $ \therefore G_0^2 < F_{n-1}^2 \le 3n^2 $

    $ \because G_0 \in \mathbb{N} ,F_{n-1} \in \mathbb{N} $

    $ \therefore G_0 < F_{n-1} $

    $ \therefore \max_{i=0}^{n-1}(G_i) < \min_{i=0}^{n-1}(F_i) $

有了这些东西,我们就可以将限制拆分为:

所有的数都满足 $ i^2 + P_i^2 \le 4n^2 $,且至少有 $ k $ 个数满足 $ i^2 + P_i^2 < n^2 $,也就是说在前面 $ n $ 个位置选出 $ k $ 个 $ G(x) $ 。

然后就可以进行容斥了。

什么?你不会容斥?你可以翻到最下面的补充知识

在弱化版中,我们将 $ a $ 数组从小到大进行了排序。

所以我们类比一下,考虑将 $ F $ 和 $ G $ 两个函数打包成二元组排序。由于第三条规律,我们通过如下方式打包成二元组:

  • $ i \in [0,n-1] : (G(i),F(i)) $

  • $ i \in [n,2n-1] : (F(i),0) $

接下来按第一关键字进行排序。

接下来就是求解方案数。我们可以使用 $ DP $ 求解。

设 $ f_{i,j} $ 表示在前 $ i $ 个位置上选出了 $ j $ 个 $ G(x) $ 的方案数。

在状态转移时需要用到当前数在选出的位置上的排名,所以用两个变量 $ t1 $ 和 $ t2 $,分别统计前面 $ (F(x),0) $ 和 $ (G(x),F(x)) $ 的个数。

首先枚举 $ k $,从 $ 0 $ 到 $ n $,表示在前面 $ n $ 个位置选出 $ k $ 个 $ G(x) $;

然后枚举 $ i $,从 $ 0 $ 到 $ 2n-1 $,表示已经确定了前面 $ i $ 个位置;

最后枚举 $ j $,从 $ 0 $ 到 $ k $,表示前面已经选出了 $ j $ 个 $ G(x) $;

状态转移分情况讨论:

  • 当前二元组是 $ (F(i),0) $:

    • 选择 $ F(i) $:

      • 排名:

      前面选出的 $ j $ 个 $ G(x) $ 一定比 $ F(i) $ 小;

      又因为排了序,前面的 $ t1 $ 个 $ F(x) $ 肯定也比 $ F(i) $ 小。

      所以总共有 $ j+t1 $ 个数比 $ F(i) $ 小。

      • 转移:

      $ f_{i+1,j}=f_{i+1,j}+f_{i,j} \times (F(i)-j-t1) $

  • 当前二元组是 $ (G(i),F(i)) $:

    • 选择 $ F(i) $:

      • 排名:

      由于函数单调递减,所以 $ n $ 个二元组 $ (F(x),0)\ (x \in [n,2n-1]) $ 相对 $ F(i) $ 一定排在前面;

      我们选出的所有 $ k $ 个 $ G(x) $ 都比 $ F(i) $ 小;

      之前 $ (G(x),F(x)) $ 类型的二元组选出的 $ t2-j $ 个 $ F(x) $ 也都比 $ F(i) $ 小。

      所以总共就有 $ n+k+t2-j $ 个数比 $ F(i) $ 小。

      • 转移:

      $ f_{i+1,j}=f_{i+1,j}+f_{i,j} \times (F(i)-n-k-t2+j) $

    • 选择 $ G(i) $:(注意只能选 $ k $ 个)

      • 排名:

      前面选出的 $ t1 $ 个 $ F(x) $ 一定比 $ G(i) $ 小;

      前面选出的 $ j $ 个 $ G(x) $ 也比 $ G(i) $ 小;

      总共就有 $ t1+j $ 个数比 $ G(i) $ 小。

      • 转移:

      $ f_{i+1,j+1}=f_{i+1,j+1}+f_{i,j} \times (G(i)-t1-j) $

最后综合起来求出 $ f_{2n-1,k} $,容斥即可。

代码实现

#include<bits/stdc++.h>
#define ll long long
const ll N=501;
using namespace std;

ll n,p;
ll f[N][N];
vector<pair<ll,ll>>t;//记录二元组 

ll F(ll i){//F函数 
	ll ans=2*n-1;
	while(ans>=0&&i*i+ans*ans>4*n*n)ans--;//注意是大于 
	return ans+1;
}

ll G(ll i){//G函数 
	ll ans=2*n-1;
	while(ans>=0&&i*i+ans*ans>=n*n)ans--;//注意是大于等于 
	return ans+1;
}

int main(){
	
	scanf("%lld%lld",&n,&p);
	for(ll i=0;i<2*n;i++){//预处理二元组 
		if(i<n)t.push_back({G(i),F(i)});
		else t.push_back({F(i),0});
	}
	sort(t.begin(),t.end());//对二元组按第一关键字排序 
	ll ans=0;
	for(ll k=0;k<=n;k++){
		//初始化 
		memset(f,0,sizeof(f));
		f[0][0]=1;
		
		ll t1=0,t2=0;//辅助统计变量 
		for(ll i=0;i<t.size();i++){
			for(ll j=0;j<=k;j++){
				if(!t[i].second){//(F(i),0) 
					f[i+1][j]=(f[i+1][j]+f[i][j]*(t[i].first-j-t1)%p)%p;//选F(i) 
				}else{//(G(i),F(i)) 
					if(j<k){//选了之后不能超过k个 
						f[i+1][j+1]=(f[i+1][j+1]+f[i][j]*(t[i].first-j-t1)%p)%p;//选G(i) 
					}
					f[i+1][j]=(f[i+1][j]+f[i][j]*(t[i].second-n-k-t2+j)%p)%p;//选F(i) 
				}
			}
			if(!t[i].second)t1++;
			else t2++;
		}
		//容斥 
		if(k%2)ans=(ans-f[t.size()][k]+p)%p;
		else ans=(ans+f[t.size()][k])%p;
	}
	printf("%lld",ans);
	
	return 0;
}

补充知识

容斥原理

容斥原理是一种组合数学常用的方法。

比如说,你要计算几个集合并集的大小,我们可以先将所有单个集合的大小加起来,然后减去所有两个集合相交的部分,再加回所有三个集合相交的部分,再减去所有四个集合相交的部分……依此类推,最终你就可以得出答案。

用数学公式可以表示为:

\[\left | \bigcup_{i=1}^{n}a_i \right | = \underset{T \subseteq \{1,2,...,n\}}{\sum}(-1)^{|T|-1} \left | \bigcap_{i \in T} a_i \right | \]

广义容斥原理

容斥原理求的是不满足任何性质的方案数,我们通过计算所有至少满足 $ k $ 个性质的方案数之和来计算。

同样的,我们可以通过计算所有至少满足 $ k $ 个性质的方案数之和来计算恰好满足 $ k $ 个性质的方案数。这样的容斥方法我们称之为广义容斥原理。

一般我们会用二项式反演进行计算。

二项式反演

对于函数 $ f(k) $ 和 $ g(k) $,满足:

\[g(k) = \underset{i=0}{\overset{k}{\sum}} C_k^i f(i) \]

则:

\[f(k) = \underset{i=0}{\overset{k}{\sum}} (-1)^{k-i} C_k^i g(i) \]

它一般用于"恰好"和"至少""至多"的转换式中


举个例子:

「bzoj2839」集合计数

一个有 $ n $ 个元素的集合有 $ 2^n $ 个不同子集(包含空集),现在要在这 $ 2^n $ 个集合中取出至少一个集合,使得它们的交集的元素个数为 $ k $ ,求取法的方案数模 $ 10^9+7 $。

$ 1 \le n \le 10^6 \(,\) 0 \le k \le n $。

由题列出式子:$ C_n^k (2{2{n-k}}-1) $。即钦定 $ k $ 个交集元素,则包含这 $ k $ 个的集合有 $ 2^{n−k} $ 个;每个集合可选可不选,但不能都不选。

设 $ f(i) $ 表示钦定交集元素为至少 $ i $ 个的方案数,$ g(i) $ 表示钦定交集元素恰好为 $ i $ 个的方案数,则有 $ C_n^k (2{2{n-k}}-1) = f(k) = \underset{i = k}{\overset{n}{\sum}} C_i^k g(i) $。

这个时候我们就可以利用二项式反演,求得 $ g(k) = \underset{i = k}{\overset{n}{\sum}} (-1)^{i-k} C_i^k f(i) = \underset{i=k}{\overset{n}{\sum}} (-1)^{i-k} C_i^k C_n^i (2{2{n-i}}-1) $。

这样就可以 $ O(n) $ 求出答案。

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

标签:方案,Square,题解,ll,容斥,le,ans,2n,Constraints
来源: https://www.cnblogs.com/zsc985246/p/16621307.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有