1 条题解

  • 0
    @ 2026-5-3 19:38:20

    哦吼吼,考场上写了一版答辩代码,供大家欣赏。

    首先考虑假设我们知道每个人手上的牌和每个人起始的位置,我们该如何判断得分。

    m=4nm=4npip_i 表示拥有牌 ii 的人第几个出牌,考虑拥有 mm 的那一队(假设为 AA,另一队为 BB)答案至少为一,那么考虑 m1m-1,在哪一方,如果在 AA 那直接结束 AA 队得分为 22,如果在 BB,那么看情况,就是如果 pm<pm1p_{m}<p_{m-1},则 BB 可以在第一轮看 mm 出不出,再决定 m1m-1 出不出,所以 BB 最多能得 11 分,然后如果是 pm>pm1p_m>p_{m-1}AA 队考虑用 mmm1m-1 出牌的那一轮出一定更优(否则 BB 队会得到一分),这样就需要考虑 m2m-2 是哪一队的,如果是 BB 队,则 BB 队必得一分,如果是 AA 队且 pm2>pm1p_{m-2}>p_{m-1},则 AA 队必得两分,否则要继续看 pm3p_{m-3},且当 pm2p_{m-2} 做出选择是使用 pm1p_{m-1} 和其选择同一轮……

    你会发现一个组合如果是可以被判断的情况为有一个 ii,且 pi<pi+1<pi+2<<pmp_i<p_{i+1}<p_{i+2}<\dots<p_m,队伍分别是 A:m,m2,,B:m1,m3A:m,m-2,\dots,B:m-1,m-3\dots,而且则要么 i1i-1 需要 pi1>pip_{i-1}>p_{i} 或者 i1i-1ii 所属队伍相同,要么 pi=1p_i=1

    钦定 mm 位于最后一个位置时,考虑整个得分序列应该是怎么样的(能够影响答案的位置为 imi\sim m),这样就需要分四种情况讨论(在偶数位则代表其为 AA 的,在奇数位则代表其为 BB 的,以下得分序列表示 AA 的得分序列):

    1. ii 为奇数位,i1i-1 为奇数位。

    这时候我们对 i1i-1 的位置其实是没有特别要求的然后判断得分序列明显开头在 pipmp_i\sim p_{m} 中的位置和开头在其后面的位置的得分才有可能不一样,开头在 pmp_mAA 得分应该为 11,此时 m1m-1 出牌轮次可以错开 mm,开头在 pm1p_{m-1}AA 得分应该为 22 因为此时 mm 可以在 m1m-1 时出牌的轮次时出牌,m2m-2 可以在另一轮出牌,开头在 pm2p_{m-2} 时则 BB 可以用 m1m-1m2m-2 在一轮,而让 m3m-3 在另一轮,无论 mm 在哪一轮都可以得到一分。

    然后你发现如果开头在 pjp_j,当 jj 属于 AA 时,AA 得分应该是 11,当 jj 属于 BB 时,得分为 22(除了 ii 的情况)。

    ii 的情况就是如果开头在 ii,由于我可以选择将 iii1i-1 不放在同一轮,而我们知道 i+1i+1 会选择和 ii 一轮,i+2i+2 会选择和 i+1i+1 一轮……所以另一轮最大的就是 i1i-1

    大概如下(循环了两遍后的中间部分,图中的 nn 是文章中的 mm):

    然后你可以枚举 nn 的位置,而且你知道 0101 的段数你就可以得到 ii 为多少,其它的是好推的。

    1. ii 为奇数位,i1i-1 为偶数位。

    推理和上文类似图大致为:

    需注意的一点是 i1i-1 是不能在 nnii 之间的位置的。

    3.ii 为偶数位,i1i-1 为偶数位。

    4.ii 为偶数位,i1i-1 为奇数位。

    注意 i1i-1

    还要注意一个问题就是全部都是相同的情况,我们上面这些涵盖不了全部都是相同的情况,所以需要特判。

    如果有得分为 00 且也有 22 的,则无解。

    我们上面是基于得分序列只有 1212 进行推断的,如果只有 0101,可以装换成 1212 的样子。

    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
    上传者