1 条题解
-
0
哦吼吼,考场上写了一版答辩代码,供大家欣赏。
首先考虑假设我们知道每个人手上的牌和每个人起始的位置,我们该如何判断得分。
设 , 表示拥有牌 的人第几个出牌,考虑拥有 的那一队(假设为 ,另一队为 )答案至少为一,那么考虑 ,在哪一方,如果在 那直接结束 队得分为 ,如果在 ,那么看情况,就是如果 ,则 可以在第一轮看 出不出,再决定 出不出,所以 最多能得 分,然后如果是 , 队考虑用 在 出牌的那一轮出一定更优(否则 队会得到一分),这样就需要考虑 是哪一队的,如果是 队,则 队必得一分,如果是 队且 ,则 队必得两分,否则要继续看 ,且当 做出选择是使用 和其选择同一轮……
你会发现一个组合如果是可以被判断的情况为有一个 ,且 ,队伍分别是 ,而且则要么 需要 或者 和 所属队伍相同,要么 。
钦定 位于最后一个位置时,考虑整个得分序列应该是怎么样的(能够影响答案的位置为 ),这样就需要分四种情况讨论(在偶数位则代表其为 的,在奇数位则代表其为 的,以下得分序列表示 的得分序列):
- 为奇数位, 为奇数位。
这时候我们对 的位置其实是没有特别要求的然后判断得分序列明显开头在 中的位置和开头在其后面的位置的得分才有可能不一样,开头在 时 得分应该为 ,此时 出牌轮次可以错开 ,开头在 时 得分应该为 因为此时 可以在 时出牌的轮次时出牌, 可以在另一轮出牌,开头在 时则 可以用 和 在一轮,而让 在另一轮,无论 在哪一轮都可以得到一分。
然后你发现如果开头在 ,当 属于 时, 得分应该是 ,当 属于 时,得分为 (除了 的情况)。
的情况就是如果开头在 ,由于我可以选择将 和 不放在同一轮,而我们知道 会选择和 一轮, 会选择和 一轮……所以另一轮最大的就是 。
大概如下(循环了两遍后的中间部分,图中的 是文章中的 ):

然后你可以枚举 的位置,而且你知道 的段数你就可以得到 为多少,其它的是好推的。
- 为奇数位, 为偶数位。
推理和上文类似图大致为:

需注意的一点是 是不能在 与 之间的位置的。
3. 为偶数位, 为偶数位。

4. 为偶数位, 为奇数位。

注意 。
还要注意一个问题就是全部都是相同的情况,我们上面这些涵盖不了全部都是相同的情况,所以需要特判。
如果有得分为 且也有 的,则无解。
我们上面是基于得分序列只有 进行推断的,如果只有 ,可以装换成 的样子。
Code
小清新代码
#include<bits/stdc++.h> //#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC optimize(2) //#pragma GCC optimize(3) //#pragma GCC optimize("Ofast,unroll-loops") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#include <immintrin.h> //#include <emmintrin.h> #define int long long #define ls(x) ((x)*2) #define rs(x) ((x)*2+1) #define pii pair<int,int> #define fi first #define se second #define Debug(...) fprintf(stderr, __VA_ARGS__) #define For(i,a,b) for(int i=a,i##end=b;i<=i##end;i++) #define Rof(i,a,b) for(int i=a,i##end=b;i>=i##end;i--) #define rep(i, b) for(int i=1,i##end=b;i<=i##end;i++) using namespace std; const int N=4e6+5,base=999983,Mod=1e9+7; //char buf[(1<<21)+5],*p1,*p2; //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) inline void chmx(int &x,int y){(x<y)&&(x=y);} inline void chmn(int &x,int y){(x>y)&&(x=y);} inline void Add(int &x,int y){(x=x+y+Mod)%=Mod;} inline int read(){ int f=0,x=0; char ch=getchar(); while(!isdigit(ch)){f|=(ch=='-');ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return f?-x:x; } void print(int n){ if(n<0){ putchar('-'); n*=-1; } if(n>9) print(n/10); putchar(n%10+'0'); } int n,a[N]; int fac[N],inv[N]; inline int ksm(int a,int b){ int res=1; while(b){ if(b&1) res=res*a%Mod; a=a*a%Mod; b>>=1; }return res; } inline int C(int n,int m){ if(n<m||m<0) return 0; return fac[n]*inv[m]%Mod*inv[n-m]%Mod; } int nxt[N]; int mi[N]; inline int use(int x,int y){ return C(4*n-x-y,2*n-x)*fac[2*n-x]%Mod*mi[n-x]%Mod*fac[2*n-y]%Mod*mi[n-y]%Mod; } signed main(){ // freopen("perm.in","r",stdin); // freopen("perm.out","w",stdout); // ios::sync_with_stdio(false); // cin.tie(0); cout.tie(0); int T=read(); mi[0]=1; For(i,1,N-5) mi[i]=mi[i-1]*((Mod+1)/2)%Mod; fac[0]=inv[0]=1; For(i,1,N-5) fac[i]=fac[i-1]*i%Mod; inv[N-5]=ksm(fac[N-5],Mod-2); Rof(i,N-6,1) inv[i]=inv[i+1]*(i+1)%Mod; while(T--){ n=read(); For(i,1,2*n) a[i]=read(); bool flagg=0; For(i,1,2*n) if(a[i]!=1)flagg=1; if(!flagg){ int ans=n*n%Mod*C(4*n-3,2*n-1)%Mod*fac[2*n-1]%Mod*ksm((Mod+1)/2,n-1)%Mod*fac[2*n-2]%Mod*ksm((Mod+1)/2,n-1)%Mod; if(n>=2)ans+=n*n%Mod*(n-1)%Mod*C(4*n-3,2*n-1)%Mod*fac[2*n-1]%Mod*ksm((Mod+1)/2,n-1)%Mod*fac[2*n-2]%Mod*ksm((Mod+1)/2,n-2)%Mod;ans%=Mod; printf("%lld\n",ans*2%Mod); continue; } int flag=0; For(i,1,2*n){ if(a[i]==2)flag|=1; if(a[i]==0) flag|=2; } if(flag==3){ puts("0"); continue; } if(flag==2){ For(i,1,2*n) a[i]=2-a[i]; For(i,0,2*n)a[i]=a[i+1]; a[2*n]=a[0]; } flagg=0; For(i,1,2*n) if(a[i]!=2)flagg=1; if(!flagg){ printf("%lld\n",(n*(n-1)%Mod*use(2,0)%Mod+n*fac[4*n-2]%Mod*mi[2*n-1]%Mod)%Mod); continue; } a[0]=a[2*n]; int m=0; For(i,1,2*n) if(a[i]!=a[i-1])m++; bool FLAG1=1; For(i,1,2*n)if(a[i]!=a[i-1]){ if(i%2==1&&a[i]==2); else if(i%2==0&&a[i]==1); else FLAG1=0; } int ans=0; For(i,1,2*n)a[i+2*n]=a[i]; Rof(i,4*n,1){ if(a[i]==a[i+1])nxt[i]=nxt[i+1]+1; else nxt[i]=1; } // For(i,1,2*n) cout<<a[i]<<" "; For(j,1,2*n){ if(j%2==0&&a[j]==1){ int i=4*n-m-1; if(i%2==1&&a[j+1]==1&&FLAG1&&i>2*n){ int L=(4*n-i+1)/2,R=L; int x=L,y=R; ans+=(min(nxt[j+1],2*n)/2)%Mod*C(4*n-x-y-1,2*n-x-1)%Mod%Mod*fac[2*n-x]%Mod*mi[n-x]%Mod*fac[2*n-y]%Mod*mi[n-y]%Mod;ans%=Mod; } i=4*n-m+1; if(i%2==1&&a[j+1]==2&&FLAG1&&i>2*n){ int L=(4*n-i+1)/2,R=L; int x=L+1,y=R; ans+=(n-min(nxt[j+1],2*n)/2-L+Mod)*C(4*n-x-y,2*n-x)%Mod*fac[2*n-x]%Mod*mi[n-(x)]%Mod*fac[2*n-y]%Mod*mi[n-y]%Mod%Mod;ans%=Mod; ans+=(L)%Mod*C(4*n-x-y,2*n-x)%Mod*fac[2*n-x]%Mod*mi[n-(x-1)]%Mod*fac[2*n-y]%Mod*mi[n-y]%Mod%Mod;ans%=Mod; } i=4*n-m; if(i%2==0&&a[j+1]==2&&FLAG1&&i>2*n){ int L=(4*n-i+1)/2+1,R=L-1; int x=L,y=R; ans+=(min(nxt[j+1],2*n)/2)%Mod*C(4*n-x-y-1,2*n-x-1)%Mod%Mod*fac[2*n-x]%Mod*mi[n-x]%Mod*fac[2*n-y]%Mod*mi[n-y]%Mod;ans%=Mod; } i=4*n-m; if(i%2==0&&a[j+1]==1&&FLAG1&&i>2*n){ int L=(4*n-i+1)/2+1,R=L-1; int x=L,y=R+1; ans+=(n-min(nxt[j+1],2*n)/2-R+Mod)*C(4*n-x-y,2*n-x)%Mod*fac[2*n-x]%Mod*mi[n-x]%Mod*fac[2*n-y]%Mod*mi[n-y]%Mod; ans+=(R)%Mod*C(4*n-x-y,2*n-x)%Mod*fac[2*n-x]%Mod*mi[n-x]%Mod*fac[2*n-y]%Mod*mi[n-(y-1)]%Mod;ans%=Mod; } } } printf("%lld\n",ans); } #ifdef LOCAL Debug("\nMy Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC); #endif return 0; }注意到这篇题解是在愚人节所写的,所以考场上认为这是代码很少 Ad hoc 题
(可能是我写多了)。
- 1
信息
- ID
- 11499
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者