题解-Atcoder_agc005D ~K Perm Counting
Problem
题意概要:给出\(n,k\),求合法的排列个数,其中合法定义为任何数字所在位置与自身值差的绝对值不为\(k\)(即求排列\(\{A_i\}\),使得\(\forall i\in[1,n],|a_i-i|\not =k\)
Solution
刚看这道题时除了全集取反搞容斥外没有任何思路啊
\(f_i\)表示排列中至少有\(i\)对冲突的方案数,一对冲突定义为存在一个\(i\)使得\(|a_i-i|=k\)
考虑全集取反,加上一点点容斥思想可得
\]
至于怎么得到 \(f_i\),就是这道题难点所在,关键思路是画图
构建一个二分图:
- 其中 \(i\) 为数值 \(i\),\(i'\) 为 \(i\) 在排列中的位置编号
- 构建边为冲突,即所有 \(i'\) 要和 \(i\pm k\) 连边
就像这样(模拟 \(n=4,k=1\) 的情况):

发现这个二分图中其实只有\(2k\)条链,于是可以对这\(2k\)条链进行Dp
在某条链上:设\(g[i][j][0/1]\)表示考虑前\(i\)个点,且已经有\(j\)对冲突,\(i\)号与\(i+1\)号连与不连的方案数,得出转移方程:
\]
对于每条链的\(f[i]\)即为\(g[end][i][0]+g[end][i][1]\)(\(end\)为链的末尾),最后合并\(2k\)条链的时候可以玩背包
但实际上有个小技巧,就是将\(2k\)条链首尾顺次相接,在两条链的交界处不转移第二个方程即可
Code
#include <cstdio>
const int N=2040,p=924844033;
int f[N+N][N][2];
bool end[N+N];
int n,k,Ans,fac[N];
inline int qm(int x){return x<p?x:x-p;}
int main(){
scanf("%d%d",&n,&k);fac[0]=1;
for(int i=1;i<=n;++i)fac[i]=1ll*fac[i-1]*i%p;
for(int i=1,tt=0,d;i<=k;++i){
d=(n-i)/k+1;
tt+=d,end[tt]=true;
tt+=d,end[tt]=true;
}
f[1][0][0]=1;
for(int i=1;i<=n+n;++i)
for(int j=0;j<=n;++j){
f[i+1][j][0]=qm(f[i][j][0]+f[i][j][1]);
if(!end[i])f[i+1][j+1][1]=f[i][j][0];
}
for(int i=0,t;i<=n;++i){
t=1ll*fac[n-i]*qm(f[n+n][i][0]+f[n+n][i][1])%p;
if(i&1)Ans=qm(Ans-t+p);
else Ans=qm(Ans+t);
}
printf("%d\n",Ans);
return 0;
}
题解-Atcoder_agc005D ~K Perm Counting的更多相关文章
- [Agc005D]K Perm Counting
[Agc005D] K Perm Counting Description 糟糕爷特别喜爱排列.他正在构造一个长度为N的排列.但是他特别讨厌正整数K.因此他认为一个排列很糟糕,当且仅当存在至少一个i( ...
- AGC 005 D - ~K Perm Counting
D - ~K Perm Counting 链接 题意: 求有多少排列对于每个位置i都满足$|ai−i|!=k$.n<=2000 分析: 容斥+dp. $answer = \sum\limits_ ...
- AGC 005D.~K Perm Counting(容斥 DP 二分图)
题目链接 \(Description\) 给定\(n,k\),求 满足对于所有\(i\),\(|a_i-i|\neq k\)的排列的个数. \(2\leq n\leq 2000,\quad 1\leq ...
- [AGC005D] ~K Perm Counting [dp]
题面 传送门 思路 首先可以明确的一点是,本题中出现不满足条件的所有的数,都是分组的 只有模$K$意义下相同的数之间才会出现不满足条件的情况,而且仅出现在相邻的情况 那么我们考虑把这个性质利用起来 我 ...
- [AT2062] ~K Perm Counting
AT2602 , Luogu 求对于 \(n\) 个数的排列 , 有多少种方案满足对于所有的 \(i\) , \(|P_i - i| != K\) , 答案对 \(924844033\) 取模 . \ ...
- 【agc005d】~K Perm Counting
题目大意 求有多少中1~n的排列,使得\(abs(第i个位置的值-i)!=k\) 解题思路 考虑容斥,\(ans=\sum_{i=0}^{n}(-1)^ig[i](n-i)!(g[i]表示至少有i个位 ...
- 【题解】K乘积
题目描述 有N个数,每个数的范围是[-50,50],现在你要从这N个数中选出K个,使得这K个数的乘积最大. 输入格式 第一行,N和K. 1 <= N <= 50. 1 <= K & ...
- 题解——UVA11997 K Smallest Sums
题面 背景 输入 输出 翻译(渣自翻) 给定K个包含K个数字的表,要求将其能产生的\( k^{k} \)个值中最小的K个输出出来 题解 k路归并问题的经典问题 可以转化为二路归并问题求解 考虑A[], ...
- 题解 P3605 [USACO17JAN]Promotion Counting P
分块\(yyds\) ----关于线段树合并的题我用分块过掉这件事 题目传送门 先说正解 正解当然是线段树合并等一类做法了 至于解析...出门右转题解区第一篇 (就是他让我看不懂,然后用分块打的\(Q ...
随机推荐
- 面向对象【day07】:析构函数(六)
二.析构函数 一.概述 析构函数,第一次听说这个函数的名称,那这个函数到底是干嘛的呢?什么才是析构函数呐? 定义:在实例销毁的时候调用的函数 二.析构函数定义 2.1 定义 1 2 3 4 5 6 7 ...
- Spring Boot笔记一 输出hello
开始学习Spring Boot了,本篇文章你可以学到 1.Spring Boot的基本配置,输出一句hello 许嵩 2.Spring boot打包成jar包 一.Spring boot的基本配置 这 ...
- 3、JPA-API
Persistence Persistence 类用于获取 EntityManagerFactory 实例,该类包含一个名为 createEntityManagerFactory 的静态方法 . cr ...
- try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}}引发的惨案
如题,ajax请求报错:try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}}引发的惨案 要么是404,要么是40 ...
- MVC的了解
MVC是一种架构模式,程序分层,分工合作,各层既相互独立,有协同工作. MVC:Model+View+Controller Model层:业务数据的信息表示,关注支撑业务的信息构成,通常是多个业务实体 ...
- Javascript async异步操作库简介
异步操作知识 在js世界中, 异步操作非常流行, nodejs就是特点基于异步非阻塞. js语言支持的异步语法包括, Promise async await generator yield. 这些语 ...
- 【bzoj 2588】Spoj 10628. Count on a tree
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- Ubuntu中安装NVIDIA显卡驱动
1.参考: https://blog.csdn.net/xunan003/article/details/81665835 https://www.cnblogs.com/luofeel/p/8654 ...
- [C++]数组处理相关函数(memcpy/memset等)
头文件:string.h或者memory.h [1]void *memcpy(void *dest, const void *src, size_t n);//数组元素拷贝 功能:从源src所指的内存 ...
- PHP之字符串匹配
strstr(string,search): strstr() 函数搜索一个字符串在另一个字符串中的第一次出现. 该函数返回字符串的其余部分(从匹配点).如果未找到所搜索的字符串,则返回 false. ...