@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. bzoj 2503 相框——思路

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2503 我也知道应该只关注度数. #include<iostream> #incl ...

  2. GIT → 00:GIT学习大纲

    1. 学习版本控制的原因 1.1 没有版本控制出现的问题 1.2 版本控制的简介 1.3 版本控制工具 2. Git 和 Svn 比较 2.1 SVN介绍 2.1.1 SVN简介 2.1.2 SVN基 ...

  3. SpringCloud微服务实战一:Spring Cloud Eureka 服务发现与注册中心(高可用实列为两个注册中心)

    微服务架构: 微服务架构的核心思想是,一个应用是由多个小的.相互独立的.微服务组成,这些服务运行在自己的进程中,开发和发布都没有依赖.不同服务通过一些轻量级交互机制来通信,例如 RPC.HTTP 等, ...

  4. NOIP模拟题17.9.26

    B 君的任务(task)[题目描述]与君初相识,犹如故人归.B 君看到了Z 君的第一题,觉得很难.于是自己出了一个简单题.你需要完成n 个任务,第i 任务有2 个属性ai; bi.其中ai 是完成这个 ...

  5. mvp例子与MVVM例子

    VMP例子 <!-- 从百度CDN上面找个jquery的链接 --> <!DOCTYPE html> <html lang="en"> < ...

  6. 【python之路16】lambda表达式

    1.lambda表达式,实际是建立一个简易的函数 下面代码中f1和f2表示是相同过程的代码 def f1(args): return args f2 = lambda args:args print( ...

  7. Laravel 安装mysql、表增加模拟数据、生成控制器

    参考中文网教程: 安装mysql.表增加模拟数据 http://www.golaravel.com/post/2016-ban-laravel-xi-lie-ru-men-jiao-cheng-yi/ ...

  8. AppScan操作手册

    AppScan操作手册 转自:http://blog.51cto.com/zhouanya/1388681   1.SQL注入 1.1.什么是sql注入 所谓SQL注入(SQL Injection), ...

  9. 拦截导弹 (最长上升子序列LIS)

    #include <iostream> #include <stdio.h> #include <algorithm> using namespace std; ] ...

  10. Python中输入和输出(打印)数据

    一个程序要进行交互,就需要进行输入,进行输入→处理→输出的过程.所以就需要用到输入和输出功能.同样的,在Python中,怎么实现输入和输出? Python3中的输入方式: Python提供了 inpu ...