@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. TZ_16_Vue_入门案例

    1.新建一个html文件导入vue.js <script src="node_modules/vue/dist/vue.js"></script> 2.创建 ...

  2. 怎么比较两个list中相同的值个数!

    怎么比较两个list中相同的值个数!int count=0;for(int i=0;i<list1.size();i++){ for(int j=0;j<list2.size();j++) ...

  3. 在C#应用中使用Common Logging日志接口

    我在C#应用中一般使用log4net来记录日志,但如果项目中有个多个工程,那么没有工程都需要引用log4neg,感觉很不爽.不过今日在开spring.net的时候,看到了有个通用日志接口Common ...

  4. 锋利的JQuery学习之JQuery中的事件

    一.加载DOM 在页面加载完毕之后,浏览器会通过javascript为dom元素添加事件,在常规的javascript中使用window.onload方法,而在jQuery中使用的是$(documen ...

  5. jnhs 无法提交断点LineBreakpoint hibernate4CURD : -1, 原因是: 找不到 URL 'file:/E:/版本控制/Design-java/hibernate4CURD/' 的源根目录。请验证项目源的设置。

    无法提交断点LineBreakpoint hibernate4CURD : -1, 原因是: 找不到 URL 'file:/E:/版本控制/Design-java/hibernate4CURD/' 的 ...

  6. IntelliJ IDEA 17 创建maven项目

    参考博客: https://yq.aliyun.com/articles/111053# 部署服务器时  没有Tomcat Server选项

  7. GIT → 11:Git 工作流与实战演练

    GIT → 11:Git 工作流与实战演练

  8. oracle 监听配置文件路径

    app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN listener.ora tnsnames.ora 配置监听直接在 tnsnames.o ...

  9. (转)Sql server中 如何用sql语句创建视图

    1.视图的作用 视图的作用: 第一点:使用视图,可以定制用户数据,聚焦特定的数据. 解释:     在实际过程中,公司有不同角色的工作人员,我们以销售公司为例的话,     采购人员,可以需要一些与其 ...

  10. ubuntu16.04上在使用搜狗输入法时,按shift不能正常切换中英文

    问题描述: ubuntu16.04上在使用搜狗输入法时,不知道把什么组合键给错按了,导致了按shift不能正常切换中英文,这是一件很烦恼的事儿! 解决步骤: 1,终端输入打开: fcitx-confi ...