COE IV C 罚球
来自本题出题人官方题解,过了近两个月才想起来发,写得很丑,赛时果然被爆标了。
题意
一开始有一个带
设上一个点返回的状态为
- 若
x=1 ,则这个环上第i 个点有\dfrac{a_i}{1000} 的概率返回1 且删除这个点,有\dfrac{b_i}{1000} 的概率返回1 但保留这个点,有\dfrac{1000-a_i-b_i}{1000} 的概率返回2 且保留这个点。 - 若
x=2 ,则这个环上第i 个点有\dfrac{a_i+b_i}{1000} 的概率返回1 且删除这个点,有\dfrac{1000-a_i-b_i}{1000} 的概率返回2 且保留这个点。
初始
求只剩一个点的期望操作次数,若期望次数为无穷大,输出
前置知识
期望,状压,高斯消元。
子任务 1
很明显,一开始就只有一个点,期望改变状态次数为
期望得分
子任务 2
这时每个点肯定会返回
期望得分
子任务 3
这时每个点肯定会返回
期望得分
子任务 4
这时每个点肯定会返回
期望得分
子任务 5
这时
期望得分
子任务 6
这时每个点都本质相同,且没有任何点返回
得出
期望得分
子任务 7
这时每个点仍然本质相同,设
那么有
得出
期望得分
子任务 8
其实就是子任务
解得
期望得分
子任务 9
进入正题,由于
从这里开始
设
这就是题目中的定义,
这样,可以考虑对于每一个
至于怎么高斯消元,需要对上述的式子进行变形:
这样就能够把高斯消元矩阵构造出来了,大小为
尤其需要注意的是如果出现了除以
朴素的高斯消元复杂度为
期望得分
子任务 10
由于
期望得分
子任务 11
发现这个矩阵是个稀疏矩阵,每列非
期望得分
标程
//去掉注释后长度:2053字节
#include<ctime>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll p=1e6+33;
const ll N=18;
int read(){
char c;
int x=0,f=1;
while(!isdigit(c=getchar()))
f-=2*(c=='-');
while(isdigit(c)){
x=x*10+f*(c-48);
c=getchar();
}
return x;
}
ll n,t,k,a[21],b[21],f[1<<N][21];
ll l[1<<N],g[1<<N],c[37][37],s[37];
ll inv[p];
void gauss(ll n){
for(ll i=0;i<n;++i){
ll t=i;
for(ll j=i;j<n;++j){
if(c[j][i]){
t=j;
break;
}
}
if(!c[t][i])
continue;
swap(c[i],c[t]);
for(ll j=i+1;j<n;++j){
if(!c[j][i])//优化
continue;
ll x=c[j][i]*inv[c[i][i]];
for(ll k=i;k<=n;++k){
if(~c[j][k])
c[j][k]=(c[j][k]-x*c[i][k]%p+p)%p;
}
}
}
for(ll i=n-1;~i;--i){
if(!c[i][i]||!~c[i][n])
s[i]=-1;//这里的-1即为特殊值,需要特判
else
s[i]=c[i][n]*inv[c[i][i]]%p;
if(!i)
continue;
for(ll j=i-1;~j;--j){
if(~c[j][n]&&(~s[i]||!c[j][i]))//仍然需要特判-1
c[j][n]=(c[j][n]-c[j][i]*s[i]%p+p)%p;
else
c[j][n]=-1;
c[j][i]=0;
}
}
}
int main(){
n=read();
t=read();
inv[1]=1;
k=1<<n;
for(ll i=2;i<p;++i)
inv[i]=(p-p/i)*inv[p%i]%p;//线性处理逆元
for(ll i=0;i<n;++i){
a[i]=read()*inv[1000]%p;//提前进行转化
b[i]=read()*inv[1000]%p;
}
for(ll i=1;i<k;++i)
l[i]=l[i^(i&-i)]+1;
for(ll i=0;i<n;++i)
g[1<<i]=i;
for(ll i=1;i<k;++i){
if(l[i]==1)
continue;
memset(c,0,sizeof(c));//初始清空矩阵
for(ll j=0,t=i;t;t^=t&-t,++j){
ll x=g[t&-t];
c[j*2][j*2]=1;
c[j*2+1][j*2+1]=1;
c[j*2][(j*2+2)%(l[i]*2)]=(p-b[x]%p)%p;
c[j*2][(j*2+3)%(l[i]*2)]=(a[x]+b[x]-1+p)%p;//由于一开始进行了处理,所以就不再是a[x]+b[x]-1000了
c[j*2+1][(j*2+3)%(l[i]*2)]=(a[x]+b[x]-1+p)%p;
if(~f[i^(1<<x)][j%(l[i]-1)]||!a[x])
c[j*2][l[i]*2]=(a[x]*f[i^(1<<x)][j%(l[i]-1)]+1)%p;
else
c[j*2][l[i]*2]=-1;
if(~f[i^(1<<x)][j%(l[i]-1)]||!(a[x]+b[x]))
c[j*2+1][l[i]*2]=((a[x]+b[x])*f[i^(1<<x)][j%(l[i]-1)]+1)%p;
else
c[j*2+1][l[i]*2]=-1;
//c[j*2]为f所对应的位置,c[j*2+1]为g所对应的位置
}
gauss(l[i]*2);
for(int j=0;j<l[i];++j)
f[i][j]=s[j*2];
}
printf("%lld\n",f[k-1][0]);
return 0;
}