最后一定存在一个分界点,满足在分界点两边的点反复横跳(点多的一边会先走几步),记录所有点顺时针/逆时针到原点的前缀和,枚举分界点取 max \max max即可。
K ≤ 500 K\leq 500 K≤500直接构造 K × K K\times K K×K的矩阵,第 i i i行填 i i i。
K > 500 K>500 K>500,发现构造奇数行 c i , j = ( i + j ( m o d n ) ) + 1 c_{i,j}=(i+j\pmod n)+1 ci,j=(i+j(modn))+1,偶数行 c i , j = ( i + j ( m o d ) ) + n + 1 c_{i,j}=(i+j\pmod)+n+1 ci,j=(i+j(mod))+n+1一定合法(若 c i , j > K c_{i,j}>K ci,j>K,直接 − n -n −n)。所以 n = 2 ⌈ K 4 ⌉ n=2\lceil\frac{K}{4}\rceil n=2⌈4K⌉(强制有偶数行)
期望的DP十分套路:
设 f [ i ] [ j ] f[i][j] f[i][j]表示 a i > a j a_i>a_j ai>aj的概率,每次操作涉及到的转移是 O ( n ) O(n) O(n)的。
求出总期望再乘上 2 Q 2^Q 2Q即可。
考虑可以被翻转的 1 1 1需要满足的条件,要么左右都是 1 1 1,要么有且只有一边与一个 0 0 0相邻。
发现原序列中存在的所有连续的 0 0 0(或连续的 1 1 1)的这些段永远存在(不可能 101 101 101变成 111 111 111),且可能会在原来的若干段中分割出新的不同的子段(如 111 → 101 111\to101 111→101,多了一个 0 0 0段)
接着需要一步神仙转化:
在 01 01 01之间加一个红色隔板, 10 10 10之间加一个蓝色隔板,序列就是一堆红蓝相间的隔板,且设两端都有无穷个隔板。
每次取反相当于把某个隔板移动一位,且隔板间不能互相跨越,即相对位置保持不变。
所以知道了最终态的每个隔板的位置后,所有初始隔板是和其一一对应的,最小的移动代价就是对应隔板的位置之差。
枚举在序列开头/末尾多插了 i ( 0 ≤ i ≤ n ) i(0\leq i\leq n) i(0≤i≤n)个隔板的代价,取 min \min min即可。复杂度 O ( n 2 ) O(n^2) O(n2)
巧妙的值域上DP
不考虑 A 2 i − 1 ≠ − 1 A_{2i-1}\neq -1 A2i−1̸=−1且 A 2 i ≠ − 1 A_{2i}\neq -1 A2i̸=−1的位置,剩下的为 ( − 1 , x ) , ( x , − 1 ) , ( − 1 , − 1 ) (-1,x),(x,-1),(-1,-1) (−1,x),(x,−1),(−1,−1)的情况。
由于 1 − 2 N 1-2N 1−2N的数都会被选用,考虑值域序列 1 − 2 N 1-2N 1−2N, min ( A 2 i − 1 , A 2 i ) \min(A_{2i-1},A_{2i}) min(A2i−1,A2i)和 max ( A 2 i − 1 , A 2 i ) \max(A_{2i-1},A_{2i}) max(A2i−1,A2i)的匹配类似于括号序列:
具体来说,倒序DP(正序似乎也可以,不过倒着更好理解),设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示完值域 i − 2 N i-2N i−2N,还有 j j j个普通右括号, k k k个带标号右括号未匹配的方案数,具体转移见代码。
注意这里并非传统意义上的括号匹配——所有右括号是等价的(包括有标号的),同一个左括号( min ( A 2 i − 1 , A 2 i ) \min(A_{2i-1},A_{2i}) min(A2i−1,A2i))匹配不同右括号的情况是等价的( B i B_i Bi一样),所以实际上DP的是左括号的不同分配方式。
#include
using namespace std;
const int mod=1e9+7;
typedef long long ll;
int n,a[305],ans,m,num,frc=1;
int f[2][305][305],typ[605];
inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
int main(){
int i,j,k,pr=0;
scanf("%d",&n);m=n+n;
for(i=1;i<=m;++i) scanf("%d",&a[i]);
for(i=1;i<=m;i+=2)
if((a[i]==-1)||(a[i+1]==-1)){
num+=(((~a[i])||(~a[i+1]))^1);
if(~a[i]) typ[a[i]]=1;if(~a[i+1]) typ[a[i+1]]=1;
}else typ[a[i]]=typ[a[i+1]]=2;
for(i=1;i<=num;++i) frc=(ll)frc*i%mod;
f[0][0][0]=1;num=0;
for(i=m;i;--i) if(typ[i]!=2){
pr^=1;memset(f[pr],0,sizeof(f[pr]));
for(j=0;j<=num;++j)
for(k=0;j+k<=num;++k) if(f[pr^1][j][k]){
if(typ[i]){
ad(f[pr][j][k+1],f[pr^1][j][k]);
if(j) ad(f[pr][j-1][k],(ll)f[pr^1][j][k]%mod);
}else{
ad(f[pr][j+1][k],f[pr^1][j][k]);
if(k) ad(f[pr][j][k-1],(ll)k*f[pr^1][j][k]%mod);
if(j) ad(f[pr][j-1][k],f[pr^1][j][k]);
}
}
num=min(num+1,m>>1);
}
printf("%d",(ll)frc*f[pr][0][0]%mod);
}