CF285D.Permutation Sum
想了很久觉得自己做法肯定T啊,就算是CF机子的3s时限,但我毕竟是 O ( C(15,7)*7!*log ) ....
果然在n=15的点T了...贱兮兮地特判了15过掉了,结果发现题解说就是打表...
(卒,享年16岁)
总之啊总之,要灵活啊
回归机房以后发现Div2的D都要想一个世纪了......不过感觉这题真的挺好的?
命不久矣,所以想最后写写题解吧。
题目大意:求满足 a+b=c( a,b,c均为长度为n的排列)的有序对{a,b}的对数
(说明:a,b,c均为0~(n-1)的排列 +运算为题中定义的+的等价修改 即ci=(ai+bi)mod n )
∆初步分析,有 2*n*(n-1)/2 = n*k + n*(n-1)/2 (k为整数) 则有 k=(n-1)/2 则n必须为奇数 否则答案为0
∆显然,{a,c}和{a,b}是一一对应的,所以我们不妨求{a,c}的有序对数(实际上这个转换并没有什么用处,只是我感觉爽....)
∆进一步化简,不妨将a固定为{0,1,2...n-1},则最终所求方案数* n! 即为答案。
∆考虑c需要满足的条件:
(1)i-ci=j-cj(mod n) 对于任意 i!=j 均不成立
(2)ci为0~n-1 且互不相同
(2)较容易解决,记录出现的数字即可。考虑如何满足(1)。想象你是在玩一个类似数独的游戏,在一个一个填数字,那么你只要保证:1.已经填上的数字彼此之间满足(1).(2) 2.新填入的第i+1个数字和前i个数字不重复、不冲突。
由此,我们可以像填数独一样,列出下一个格子不能取的值。那么我们就有一个大致思路,即状压,记录两维状态v1,v2(即由条件(1)、(2),下一位不能取的数字有哪些)。转移只需枚举下一位的可行数字x,在v1并入x,在v2并入x并循环右移1位( ci !=( val=cj-j+i ) ci+1 != (val+1=cj-j+i+1) ) 。
∆然鹅,这样复杂度很高(上界可达 O(n*22n) ?总之打表估计都GG),因此我们考虑进一步优化。
优化的本质就是探寻性质。我们发现,对于f[v1][v2]>0,v1和v2中的1个数一定相同,即在v2中并入数字时一定不会并入一个已经存在的位。可以用反证法证明,若并入ci对ci+1的影响时,该位已有cj对ci+1的影响,那么i、j两位就一定不符合(2)。
也就是说,v1,v2是可以「拆分」的。
∆「拆分」具体是什么意思呢?我们来模拟一下。
假设n=7,当前已经放了4个数:
v1=1100110
v2=1001011
现在我们挨个放入剩下的数字。例如:
v1=1120110
v2=0210111
v1=1123110
v2=2131110
v1=1123114
v2=1311142
将末状态和初状态做差,得到:
v1=0023004
v2=0300042
即
v1=0011001
v2=0100011
我们发现 对于初状态的{v1,v2} 差状态即为{1111111^v1, turn(1111111^v1,3) }
(turn(j,ct)表示将j循环右移ct位)
∆于是 我们就可以开心地折半搜索了!复杂度见第一行
(以下是打表代码,如果直接复制会在n=15的点TLE)
#include <bits/stdc++.h>
using namespace std; #define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)
#define mp make_pair
#define fir first
#define sec second typedef long long ll;
typedef pair<int,int> pii; const int p=,V=1e6+; int n,full,semi,turn[V];
map<pii,int>f[];
map<pii,int>::iterator it; int rev(int j){//j循环右移1位
int ans=;
if(j>=semi){
ans=;
j-=semi;
} return ans|(j<<);
} int main(){
scanf("%d",&n); if(n==){
printf("");
return ;
} if(n%==){
printf("");
return ;
} full=(<<n)-;
semi=(<<(n-)); int u=(n>>); f[][mp(,)]=; //多出的一维[0/1]是在愚蠢地省空间...
bool oi=;
rep(o,,u){
f[!oi].clear(); for(it=f[oi].begin();it!=f[oi].end();++it){
pii P=it->fir;int val=it->sec;
int L=P.fir,R=P.sec; int j=(L|R);
if(j==full) continue; rep(i,,n-) if( ( (<<i)&L ) == && ( (<<i)&R ) == )
(f[!oi][mp( ( L|(<<i) ) , rev( R|(<<i) ) )]+=val)%=p; } oi=!oi;
} int pre=(<<(u+))-,suf=full^pre;
rep(i,,full) turn[i]=((i&pre)<<u)|((i&suf)>>(u+));
//turn[i]即i循环右移(n/2)位 ll ans=;
for(it=f[oi].begin();it!=f[oi].end();++it){
pii P=it->fir;ll val=it->sec;
int L=P.fir,R=P.sec; (ans+=val*f[!oi][mp(full^L,turn[full^R])]%p)%=p;
} rep(i,,n) (ans*=i)%=p; printf("%lld",ans); return ;
}
CF285D.Permutation Sum的更多相关文章
- CF285D.D. Permutation Sum
CF285D. Permutation Sum 题目 大意 寻找a,b两个排列从0到n-1,有c[i]=(a[i]+b[i])%n+1,使得c[i]也为全排列的排列方式 思路 a中元素和b中元素的对应 ...
- codeforces 285 D. Permutation Sum 状压 dfs打表
题意: 如果有2个排列a,b,定义序列c为: c[i] = (a[i] + b[i] - 2) % n + 1 但是,明显c不一定是一个排列 现在,给出排列的长度n (1 <= n <= ...
- SPOJ:Elegant Permuted Sum(贪心)
Special Thanks: Jane Alam Jan*At moment in University of Texas at San Antonio - USA You will be give ...
- Codeforces Round #175 (Div. 2)
A. Slightly Decreasing Permutations 后\(k\)个倒序放前面,前\(n-k\)个顺序放后面. B. Find Marble 模拟. C. Building Perm ...
- Codeforces Round #175 (Div. 2) A~D 题解
A.Slightly Decreasing Permutations Permutation p is an ordered set of integers p1, p2, ..., pn, c ...
- combination sum、permutation、subset(组合和、全排列、子集)
combination sum I.permutation I.subsets I 是组合和.全排列.子集的第一种情况,给定数组中没有重复的元素. combination sum II.permut ...
- UVA11525 Permutation[康托展开 树状数组求第k小值]
UVA - 11525 Permutation 题意:输出1~n的所有排列,字典序大小第∑k1Si∗(K−i)!个 学了好多知识 1.康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+ ...
- 266. Palindrome Permutation
题目: Given a string, determine if a permutation of the string could form a palindrome. For example,&q ...
- Educational Codeforces Round 7 D. Optimal Number Permutation 构造题
D. Optimal Number Permutation 题目连接: http://www.codeforces.com/contest/622/problem/D Description You ...
随机推荐
- js查漏补缺
js中: 1.对空(Null).未定义(Undefined).Symbol .函数(Function) 都是数据类型(js不像java中,声明了变量会有默认值,在js中只声明变量而没有赋值的时候,类型 ...
- Django 安装配置
1-安装Python3.6.1 Python2.x 与3.x的版本在语法上稍有不同,区别在于输出语句的不同,这个可以看相关的文档. Python3.6.1,可以在Python的官网上下载:https: ...
- python基础之作业3----三级菜单小练习
data = { "华为技术":{ "产品与解决方案":{ "云核心网":{"云核心网研发管理部","云核心网 ...
- 理解UDP协议的首部校验和校验和
reference: https://blog.csdn.net/qiuchangyong/article/details/79945630 https://seanwangjs.github.io/ ...
- Python条件判断 if-else for循环 while循环 break continue
条件判断 if-else if-else语句是通过if 后面的是否为真,当为True,就执行if代码块后面的,如果为False,同时又有else语句,执行else后面的内容.没有else,什么都不执行 ...
- 【Shell】单行注释和多行注释
单行注释 '# ' # echo "hello" 多行注释 方法1 : << ! 这是注释1 这是注释2 这是注释3 ! 方法2 :' 这是注释1 这是注释2 这是注释 ...
- shell脚本学习总结(不断更新中)
前言:自从大学毕业参加工作以来,接触的开发工作都是在服务端完成,于是接触了比较多的Linux当做开发机使用,或多或少有一些重复性的工作,于是开始琢磨学习一些shell脚本的知识,以便处理这些繁琐的事情 ...
- C# 连蒙带骗不知所以然的搞定USB下位机读写
公司用了一台发卡机,usb接口,半双工,给了个dll,不支持线程操作,使得UI线程老卡. 懊恼了,想自己直接通过usb读写,各种百度,然后是无数的坑,最终搞定. 现将各种坑和我自己的某些猜想记录一下, ...
- jQuery中有关each方法的使用
概述: each() 方法规定为每个匹配元素规定运行的函数. 返回 false 可用于及早停止循环,相当于break. 返回 true 可以结束本次循环,相当于continue. 语法: $(sele ...
- top和nvidia-smi无法显示占用GPU的PID问题
通过nvidia-smi查看显卡使用情况,发现显卡在被占用,但是却没有提示占用显卡的进程id, 这时可以输入 fuser -v /dev/nvidia* 可以查看到, 再利用sudo kill -9 ...