- 很有意思的一道题目,正好这个学期自己也挺关心乒乓球的~
- \(n\leq 10^5\) 直接递推就好了。要推数学公式的话也不难。分类讨论找一下规律,注意到10平之后一定是双方各有胜负,区别只在于先后顺序,故方案数可以表示为2的次幂
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
long long f[21][12][12];
long long g[100005][2];
int a[100005],b[100005];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
if(a[i]>b[i])
{
swap(a[i],b[i]);
}
}
memset(f,0,sizeof(f));
f[0][0][0]=1;
for(int i=1;i<=min(20,n);i++)
{
if(a[i]==-1&&b[i]==-1)
{
for(int j=max(0,i-11);j<=min(i,11);j++)
{
int k=i-j;
if(i!=n&&(j==11||k==11))
{
continue;
}
if(j)
{
f[i][j][k]+=f[i-1][j-1][k];
}
if(k)
{
f[i][j][k]+=f[i-1][j][k-1];
}
f[i][j][k]%=mod;
}
}
else
{
if(a[i]<=11&&b[i]<=11&&a[i]+b[i]==i)
{
if(i!=n&&(a[i]==11||b[i]==11))
{
continue;
}
if(a[i])
{
f[i][a[i]][b[i]]+=f[i-1][a[i]-1][b[i]];
if(a[i]!=b[i])
{
f[i][b[i]][a[i]]+=f[i-1][b[i]][a[i]-1];
}
}
if(b[i])
{
f[i][a[i]][b[i]]+=f[i-1][a[i]][b[i]-1];
if(a[i]!=b[i])
{
f[i][b[i]][a[i]]+=f[i-1][b[i]-1][a[i]];
}
}
f[i][a[i]][b[i]]%=mod;
f[i][b[i]][a[i]]%=mod;
}
}
}
if(n<=20)
{
int ans=0;
for(int j=max(0,n-11);j<=min(n,11);j++)
{
if(j>=11||n-j>=11)
{
ans=(ans+f[n][j][n-j])%mod;
}
}
cout<<ans<<"\n";
}
else
{
if(a[21]==-1&&b[21]==-1||a[21]==10&&b[21]==11)
{
g[21][0]=g[21][1]=f[20][10][10];
}
else
{
g[21][0]=g[21][1]=0;
}
for(int i=22;i<n;i++)
{
if(i%2==0)
{
if(a[i]==-1&&b[i]==-1||a[i]==b[i]&&b[i]==i/2)
{
g[i][0]=(g[i-1][0]+g[i-1][1])%mod;
}
else
{
g[i][0]=0;
}
}
else
{
if(a[i]==-1&&b[i]==-1||a[i]==i/2&&b[i]==(i+1)/2)
{
g[i][0]=g[i][1]=g[i-1][0];
}
else
{
g[i][0]=g[i][1]=0;
}
}
}
if(n%2==0&&((a[n]==-1&&b[n]==-1)||(a[n]==n/2-1&&b[n]==n/2+1)))
{
cout<<(g[n-1][0]+g[n-1][1])%mod<<"\n";
}
else
{
cout<<0<<"\n";
}
}
}
return 0;
}