@description@

给定一个整数 N,统计有多少个 0~2N-1 的排列 \(P_0, P_1, ..., P_{2N-1}\) 满足:

\[N^2 \le i^2 + P_i^2 \le (2N)^2 (0 \le i < 2N)
\]

求合法排列数量 mod m。

Constraints

1≤N≤250, 2≤M≤10^9

Input

输入格式如下:

N M

Output

输出合法排列数量 mod m。

Sample Input 1

2 998244353

Sample Output 1

4

@solution@

根据条件 \(N^2 \le i^2 + P_i^2 \le (2N)^2\),我们可以求得 \(P_i\) 的上下界 \(lb_i \le P_i \le rb_i\)。

当 \(0 \le i < N\) 时,\(lb_i = \sqrt{N^2 - i^2}, rb_i = \sqrt{(2N)^2 - i^2}\)。

当 \(N \le i < 2N\) 时,\(lb_i = 0, rb_i = \sqrt{(2N)^2 - i^2}\)。

注意到当 \(i \ge N\) 时 \(lb_i\) 就始终等于 0 了。这意味着有一半元素有着相同下界。

假如 \(lb_i\) 全都为 0,是否有快捷的计算方法呢?

假如 \(lb_i\) 全都为 0,将 \(rb_i\) 从小到大排好序得到 \(rb'_i\),然后从小到大依次考虑每一个 \(rb'_i\) 的贡献。

因为较大的 \(rb'_i\) 一定包含较小的 \(rb'_j\),这意味着无论 j 选择什么,i 总是会少一个可选择的数。

\(rb'_i\) 对应可以选择 \(rb'_i + 1\) 种数(注意可以选 0),删去前面的已经被占用的就只剩\(rb'_i + 1 - i\) 种数(注意下标从 0 开始)。

那么总贡献为 \(\prod_{i=0}^{2N-1}(rb'_i + 1 - i)\)。

对于有下界的情况,考虑经典容斥一波。

枚举哪些数强制 < lb,那么那些数的限制对应变成 \(P_i < lb_i\),即 \(P_i \le lb_i - 1\)。然后就又可以使用我们上面的方法进行计数。

但是这个是指数级的算法。考虑根据题目性质进行优化。

首先只有 0 ~ N-1 这些数可能会 < lb,那么我们只容斥 0 ~ N-1 的部分。

然后,如果你打个表(或者直接观察),你会发现随着 i 增大,\(lb_i\) 与 \(rb_i\) 是递减的。

而我们计数的时候需要排序后的结果,所以这个性质的价值很大。

最后一点,对于 0 ~ N-1 这些数,有 \(\max\{lb\} <= \min\{rb\}\)。

有了这些结论,我们就可以设计我们的算法了。假设我想要求 k 个 < lb 的方案数 f(k):

N ~ 2N-1 这些数只能取 rb 为上界。排完序后那些比它们上界小的,要么是 N ~ 2N-1 中由于单调性而较小的,要么是 0 ~ N-1 中取 lb-1 为上界时比较小的。

0 ~ N-1 这些数,当取 lb-1 为上界时大致同上,要么是 0 ~ N-1 中由于单调性而较小的,要么是 N ~ 2N-1 较小的。

而取 rb 为上界时,首先有 N ~ 2N-1 由于单调性所以所有都比它小,其次那 k 个取 lb-1 为上界的一定比它小(由上面的性质),最后有 0 ~ N 中那些由于单调性而比它小的。

由此,我们将 0 ~ N-1 以 lb-1 为第一关键字,rb 为第二关键字; N ~ 2N-1 以 rb 为第一关键字,0 为第二关键字,全部进行排序。

从小到大作 dp,令 dp(i, j) 表示前 i 个选出 j 个 < lb 的方案数。最后 f(k) = dp(2N, k)。

总方案为 f(0) - f(1) + f(2) - f(3) + ...

时间复杂度 O(n^3)。

@accepted code@

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define mp make_pair
#define fi first
#define se second
typedef pair<int, int> pii;
const int MAXN = 500;
int N, M;
int add(int x, int y) {return (x + y) % M;}
int mul(int x, int y) {return 1LL*x*y % M;}
int sub(int x, int y) {return add(x, M-y);}
int f[MAXN + 5][MAXN + 5]; pii a[MAXN + 5];
int solve(int t) {
int cnt1 = 0, cnt2 = 0;
f[0][0] = 1;
for(int i=0;i<2*N;i++) {
if( a[i].se == 0 ) {
for(int j=0;j<=cnt2;j++)
f[i+1][j] = mul(f[i][j], a[i].fi - (cnt1 + j) + 1);
cnt1++;
}
else {
f[i+1][0] = 0;
for(int j=0;j<=cnt2;j++)
f[i+1][j+1] = mul(f[i][j], a[i].fi - (cnt1 + j) + 1);
for(int j=0;j<=cnt2;j++)
f[i+1][j] = add(f[i+1][j], mul(f[i][j], a[i].se - (N + cnt2 - j + t) + 1));
cnt2++;
}
}
return f[2*N][t];
}
int main() {
scanf("%d%d", &N, &M);
for(int i=0;i<N;i++) {
a[i].fi = 0, a[i].se = 2*N - 1;
while( a[i].fi*a[i].fi + i*i < N*N ) a[i].fi++; a[i].fi--;
while( a[i].se*a[i].se + i*i > 4*N*N ) a[i].se--;
}
for(int i=N;i<2*N;i++) {
a[i].fi = 2*N - 1, a[i].se = 0;
while( a[i].fi*a[i].fi + i*i > 4*N*N ) a[i].fi--;
}
sort(a, a + 2*N);
int ans = 0;
for(int i=N;i>=0;i--)
ans = sub(solve(i), ans);
printf("%d\n", ans);
}

@details@

抱歉,我不会组合计数.jpg。

@atcoder - AGC036F@ Square Constraints的更多相关文章

  1. [Atcoder AGC029C]Lexicographic constraints

    题目大意:给定$n$个字符串的长度$a_i$,问至少用几种字符可以构造出字符串$s_1\sim s_n$,满足$|s_i|=a_i$且$s_1<s_2<\cdots<s_n$. $ ...

  2. AtCoder刷题记录

    构造题都是神仙题 /kk ARC066C Addition and Subtraction Hard 首先要发现两个性质: 加号右边不会有括号:显然,有括号也可以被删去,答案不变. \(op_i\)和 ...

  3. hs-black 杂题选讲

    [POI2011]OKR-Periodicity 考虑递归地构造,设 \(\text{solve(s)}\) 表示字典序最小的,\(\text{border}\) 集合和 \(S\) 的 \(\tex ...

  4. AtCoder Grand Contest 036

    Preface 这篇已经鸽了好久的说,AGC037都打完了才回来补所以题目可能都记不大清楚了,如有错误请指正 这场感觉难度远高于上一场,从D开始就不会了,E没写(看了题解都不会写),F就是抄曲明姐姐的 ...

  5. AtCoder Grand Contest 036 简要题解

    从这里开始 比赛目录 Problem A Triangle 考虑把三角形移到和坐标轴相交,即 然后能够用坐标比较简单地计算面积,简单构造一下就行了. Code #include <bits/st ...

  6. ZROI 暑期高端峰会 A班 Day1 组合计数

    AGC036F Square Constriants 一定有 \(l_i<p_i\le r_i\). 考虑朴素容斥,枚举每个数是 \(\le l_i\) 还是 \(\le r_i\).对于 \( ...

  7. AtCoder Beginner Contest 069【A,水,B,水,C,数学,D,暴力】

    A - K-City Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement In K-city, ...

  8. AtCoder Beginner Contest 088 (ABC)

    A - Infinite Coins 题目链接:https://abc088.contest.atcoder.jp/tasks/abc088_a Time limit : 2sec / Memory ...

  9. AtCoder Beginner Contest 087 (ABC)

    A - Buying Sweets 题目链接:https://abc087.contest.atcoder.jp/tasks/abc087_a Time limit : 2sec / Memory l ...

随机推荐

  1. Thinkphp 数据库配置参数

    mysql配置 'DB_USER' => array( 'DB_TYPE' => 'mysql', 'DB_HOST' => '127.0.0.1', 'DB_NAME' => ...

  2. Markdown文档使用

    Markdown使用 一.markdown标题:1级-6级 一级 #空格 二级 ##空格 三级 ###空格 ... 六级 ######空格 二.代码块 print("hello world! ...

  3. 实时查看linux网卡流量 的base脚本

    #!/bin/bash " ] do eth=$ RXpre=$(cat /proc/net/dev | grep $eth | tr : " " | awk '{pri ...

  4. 提升mysql服务器性能(复制原理与拓扑优化)

    原文:提升mysql服务器性能(复制原理与拓扑优化) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/details/9008171 ...

  5. go语言:获取字符串长度

    go语言字符串底层由字节数组实现,使用UTF-8编码,初始化以后不能被修改 获取字符串长度 一.当字符串中所有字符都是单字节字符时,使用 len 函数获取字符串的长度 package main imp ...

  6. Robbin负载均衡

    Robbin是在Spring Cloud中的一个组件,是由Netfix发布的负载均衡器,有助于控制HTTP和TCP客户端的行为.它给我们提供了默认的轮询.随机等负载均衡算法.同时也可以由我们定义自己的 ...

  7. python中操作json

    1.导入json包 import json 2.打开json文档 fp = open(jsonpath) 3.读取json文件 data=json.load(fp) 4.获取json的值 data[' ...

  8. 数据库Mysql监控及优化

    在做 性能测试的时候数据最重要,数据来源于哪里呢,当然是数据库了,数据库中,我们可以知道,数据从磁盘中要比从缓存中读取数据的时间要慢的多的多,还可以知道,同样的一个sql语句,执行的效率也不一样,这是 ...

  9. 使用Gradle构建项目

    使用gradle构建项目之前,咱们先聊聊maven,使用maven构建项目和配置主要 接下来正式使用gradle来构建项目的和步骤: 1.下载源码 2.下载gradle 1.下载地址:https:// ...

  10. React项目动态设置title标题

    在React搭建的SPA项目中页面的title是直接写在入口index.html中,当路由在切换不用页面时,title是不会动态变化的.那么怎么让title随着路由的切换动态变化呢?1.在定义路由时增 ...