当前位置: 代码迷 >> 综合 >> 【AtCoder】【容斥】AGC036F-Square Constraints
  详细解决方案

【AtCoder】【容斥】AGC036F-Square Constraints

热度:77   发布时间:2023-11-21 06:46:16.0

AtCoder AGC036F Square Constraints

题目大意

◇题目传送门◆

求有多少种0002N?12N-12N?1的排列ppp,对于任意一个位置iii总有N2≤pi2+i2≤(2N)2N^2\le {p_i}^2+i^2\le (2N)^2N2pi?2+i2(2N)2

分析

很容易想到把限制拆成pi2+i2<N2{p_i}^2+i^2<N^2pi?2+i2<N2pi2+i2≤4N2{p_i}^2+i^2\le 4N^2pi?2+i24N2。这样我们就可以求出分别满足两个限制的方案数,最后作差就是了。

但这样做似乎仍然不好算,那么我们考虑容斥,即将限制分解成至少有kkk个数满足pi2+i2≤N2?1{p_i}^2+i^2\le N^2-1pi?2+i2N2?1,且所有的数都满足pi2+i2≤4N2{p_i}^2+i^2\le 4N^2pi?2+i24N2


补充: 对于一个排列ppp,若我们已经知道了每个位置上的最大值aia_iai?,由于我们必须从取值范围小的数开始算,那么这个排列的方案数就是:

∏i=1N(ai?i+1)\prod_{i=1}^{N}(a_i-i+1)i=1N?(ai??i+1)


考虑如何计算这个限制的方案数。

设函数f(i)f(i)f(i)为满足i2+a2≤4N2i^2+a^2\le 4N^2i2+a24N2的最大的aaag(i)g(i)g(i)为满足i2+a2≤N2i^2+a^2\le N^2i2+a2N2的最大的aaa

不难证明g(i)g(i)g(i)只有NNN个,且两个函数都是单调递减的。

一个比较直观的想法是在前面NNN个位置中选出kkkg(i)g(i)g(i)。这样就满足条件了。

根据定义,我们可以得到对于f(i),N≤i<2Nf(i),N\le i<2Nf(i),Ni<2N,它必定是在排列中的。

那么剩下的NNN个位置,就有可能是g(i)g(i)g(i)或者f(i)f(i)f(i)了。

由于我们必须从小到大考虑每个位置,又因为任意一个g(i)g(i)g(i)一定比任意一个f(i)f(i)f(i)小,所以我们进行如下操作:

  • 0≤i<N0\le i<N0i<N时,我们将f(i),g(i)f(i),g(i)f(i),g(i)绑成二元组(g(i),f(i))(g(i),f(i))(g(i),f(i))
  • i≥Ni\ge NiN时,我们将f(i)f(i)f(i)绑成二元组(f(i),0)(f(i),0)(f(i),0)

最后排序就可以了,这样我们就可以顺序考虑而不必一位一位地算了。而计算这个方案的方法,我们采用DP。


设状态f(i,j)f(i,j)f(i,j)表示在前iii个位置上选出了jjjg(i)g(i)g(i)的方案数。

考虑如何转移:

再定义两个辅助变量c1,c2c_1,c_2c1?,c2?,分别记录在前iii个位置上二元组(f(i),0)(f(i),0)(f(i),0)的个数,(g(i),f(i))(g(i),f(i))(g(i),f(i))的个数。

对于第iii个二元组,我们分成两种情况讨论:

  • 若这个二元组是(f(i),0)(f(i),0)(f(i),0),显然我们只能够选f(i)f(i)f(i)
    • 考虑它是第几大: 在它前面有c1c_1c1?(f(i),0)(f(i),0)(f(i),0),由于排了序,这个(f(i),0)(f(i),0)(f(i),0)一定是最大的;又因为在它前面还有jjj(g(i),f(i))(g(i),f(i))(g(i),f(i)),显然f(i)f(i)f(i)肯定比这jjjg(i)g(i)g(i)大,所以这个f(i)f(i)f(i)是第c1+jc_1+jc1?+j
    • 考虑贡献: f(i,j)f(i,j)f(i,j)f(i+1,j)f(i+1,j)f(i+1,j)的贡献为f(i,j)×(f(i)?c1?cnt)f(i,j)\times(f(i)-c_1-cnt)f(i,j)×(f(i)?c1??cnt)
  • 若这个二元组是(g(i),f(i))(g(i),f(i))(g(i),f(i)),那么我们有两种选法:
    • g(i)g(i)g(i) 由于有不超过kkk个的限制,这种选法只能够在j<kj<kj<k时成立(因为我用的是刷表法)
      • 考虑排名: 在它之前有c1c_1c1?f(i)f(i)f(i)比它小,又有jjjg(i)g(i)g(i)比它小,所以它的排名是c1+jc_1+jc1?+j
      • 考虑贡献: f(i,j)f(i,j)f(i,j)f(i+1,j+1)f(i+1,j+1)f(i+1,j+1)的贡献为f(i,j)×(g(i)?c1?j)f(i,j)\times(g(i)-c_1-j)f(i,j)×(g(i)?c1??j)
    • f(i)f(i)f(i)
      • 考虑排名: 显然有i<Ni<Ni<N,又由于有NNNf(i)f(i)f(i)i≥Ni\ge NiNf(i)f(i)f(i)是单调递减的,那么我们可以知道这NNNf(i)f(i)f(i)一定是在我们选的这个f(i)f(i)f(i)的前面的。又因为任意一个f(i)f(i)f(i)都大于g(i)g(i)g(i),所以我们选出的kkkg(i)g(i)g(i)都比f(i)f(i)f(i)要小,又由于之前还有c2?jc_2-jc2??jf(i)f(i)f(i),所以它的排名为N+k+(c2?j)N+k+(c_2-j)N+k+(c2??j)
      • 考虑贡献: f(i,j)f(i,j)f(i,j)f(i+1,j)f(i+1,j)f(i+1,j)的贡献为f(i,j)×[f(i)?N?k?(c2?j)]f(i,j)\times\left[f(i)-N-k-(c_2-j)\right]f(i,j)×[f(i)?N?k?(c2??j)]

综上,我们可以算出f(2N,k)f(2N,k)f(2N,k)的结果,即有kkk个位置满足pi2+i2<N2{p_i}^2+i^2<N^2pi?2+i2<N2且所有位置均满足pi2+i2≤4N2{p_i}^2+i^2\le 4N^2pi?2+i24N2的方案数,最后容斥一下就可以了。

参考代码

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;typedef long long ll;
const int Maxn = 500;int N, Mod;vector<pair<int, int> > p;
ll f[Maxn + 5][Maxn + 5];inline int F(int i) {
    static int ret = 2 * N - 1;while(ret >= 0 && i * i + ret * ret > 4 * N * N)ret--;return ret + 1;
}
inline int G(int i) {
    static int ret = 2 * N - 1;while(ret >= 0 && i * i + ret * ret >= N * N)ret--;return ret + 1;
}int main() {
    
#ifdef LOACLfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifscanf("%d %d", &N, &Mod);for(int i = 0; i <= 2 * N - 1; i++) {
    if(i < N) p.push_back(make_pair(G(i), F(i)));else p.push_back(make_pair(F(i), 0));}sort(p.begin(), p.end());ll ans = 0;for(int k = 0; k <= N; k++) {
    memset(f, 0, sizeof f);f[0][0] = 1;int cnt1 = 0, cnt2 = 0;for(int i = 0; i < (int)p.size(); i++) {
    for(int j = 0; j <= k; j++)if(p[i].second == 0) {
    f[i + 1][j] = (f[i + 1][j] + f[i][j] * (p[i].first - j - cnt1) % Mod) % Mod;} else {
    if(j < k) f[i + 1][j + 1] = (f[i + 1][j + 1] + f[i][j] * (p[i].first - j - cnt1) % Mod) % Mod;f[i + 1][j] = (f[i + 1][j] + f[i][j] * (p[i].second - N - k - (cnt2 - j)) % Mod) % Mod;}if(p[i].second == 0) cnt1++;else cnt2++;}if(k % 2) ans = (ans - f[p.size()][k] + Mod) % Mod;else ans = (ans + f[p.size()][k]) % Mod;}printf("%lld\n", ans);return 0;
}
  相关解决方案