@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. ssh 连接vps

    默认端口22 ssh root@194.10.10.10 特定端口xxx 上面命令后面加上 "-p xxx" 就可以了

  2. git学习记录——基础概念和文件的基本操作

    夸一下git git是当前世界上最先进的分布式版本控制系统 优势: 1.不必联网 2.Git极其强大的分支管理,把SVN等远远抛在了后面. 集中式的代表CVS和SVN 分布式的代表BitKeeper, ...

  3. IDEA设置谷歌浏览器和火狐浏览器打开

    我们在软件的功能栏中选择file,然后使用鼠标点击settings,进入到软件的详细设置界面   进入后,我们可以看到很多设置项,然后我们使用鼠标依次点击左侧的tools和web browsers,进 ...

  4. Vue2.0史上最全入坑教程(下)—— 实战案例

    书接上文 前言:经过前两节的学习,我们已经可以创建一个vue工程了.下面我们将一起来学习制作一个简单的实战案例. 说明:默认我们已经用vue-cli(vue脚手架或称前端自动化构建工具)创建好项目了 ...

  5. LUOGU P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm

    传送门 解题思路 记忆化搜索,如果搜到环,就将环的大小处理出来. 代码 #include<iostream> #include<cstdio> #include<cstr ...

  6. go 文件操作 io

    package main import ( "fmt" "os" ) func main() { //打开文件 //概念说明: file 的叫法 //1. fi ...

  7. lingo 出现63. MODEL IS ILL DEFINED 解决办法

    63. MODEL IS ILL DEFINED. CHECK FOR UNDEFINED INDICES AND/OR CONDITIONS IN EXPRESSION: EXPRESSION. 还 ...

  8. python实现统计字符类型

    #字符串处理统计类型def my_func(*str): list_num = [] list_big = [] list_small = [] list_qt = [] str = input('请 ...

  9. 2018-5-4-WPF-获得触摸精度和触摸点

    title author date CreateTime categories WPF 获得触摸精度和触摸点 lindexi 2018-05-04 21:11:51 +0800 2018-5-4 21 ...

  10. Python PEP8标准

    1.编码 如无特殊情况,文件一律使用utf-8编码 如无特殊情况,文件头部必须添加# -*- coding:utf-8 -*- 标志 2.代码 统一使用四个空格缩进 每行代码不超过80个字符 自然语言 ...