这个时候考过:
当时看shadowice1984的做法,但是没有亲自写,,,
雅礼集训考试的时候鼓捣半天,被卡常到80pts,要跑9s
卡不动。
正解实际是:
3重容斥
1.随便选-一个对角线空+两个对角线空
2.2^m枚举每一个位置放不放
3.对角线空——若干个位置不空,再容斥
A.一个对角线,枚举i个放在对角线上,C(*,i)组合数,剩下的方案数是(n-sz-i)!
B.两个对角线,按圈DP,f[i][j]i圈,选了j个在对角线上方案数。枚举四个角放一个、对角放两个,都不放7种情况。
常数很小。
#include#define reg register int#define il inline#define fi first#define se second#define mk(a,b) make_pair(a,b)#define numb (ch^'0')#define pb push_back#define solid const auto &#define enter cout< using namespace std;typedef long long ll;template il void rd(T &x){ char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}template il void output(T x){ if(x/10)output(x/10);putchar(x%10+'0');}template il void ot(T x){ if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}template il void prt(T a[],int st,int nd){ for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}namespace Modulo{const int mod=10007;il int ad(int x,int y){ return x+y>=mod?x+y-mod:x+y;}il int sub(int x,int y){ return ad(x,mod-y);}il int mul(int x,int y){ return (ll)x*y%mod;}il void inc(int &x,int y){x=ad(x,y);}il void inc2(int &x,int y){x=mul(x,y);}il int qm(int x,int y=mod-2){ int ret=1;while(y){ if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}template il int ad(const int a,const int b,const Args &...args) { return ad(ad(a,b),args...);}template il int mul(const int a,const int b,const Args &...args) { return mul(mul(a,b),args...);}}using namespace Modulo;namespace Miracle{const int N=104;const int M=12;int n,m;int X[M],Y[M];int hk[N],lk[N];int f[N][N];int c[N][N];int jie[N],inv[N];int C(int n,int m){ if(n<0||m<0||n >(i-1))&1){ if(X[i]==Y[i]) fl1=false; if(X[i]+Y[i]==n+1) fl2=false; if(hk[X[i]]) fl=false; ++hk[X[i]]; if(lk[Y[i]]) fl=false; ++lk[Y[i]]; } }// cout<<" s "< <<" "<<<" "< <<" "< <
疯狂容斥
对角线至少选择一个这种很麻烦。必须考虑有没有选择。
格子都不能选很麻烦。要考虑给后面预留,只能状压
对角线>=1——>都是0
都是0——>有一些放了
格子都不能选——>一些可以选
以及按圈DP
对称,方便同时处理可能产生矛盾的情况,避免状压。