玩个球
玩个球
《关于我继“贞难调”后又命名了一道“贞卡常”的这件事》
其实这道题部分分还是比较好拿的。
对于subtask3,明显就是一个都不拿,而
就是全都拿。
对于subtask4,如果全为W就输出,否则就输出
。
然后我们就愉快的拿到2pts了。
对于subtask5,就直接统计这个W被拿到的概率,通过容斥可以求出,其概率为
对于subtask6,也可以通过上面方法得到,不过有些麻烦。不过因为数据过水,直接输出k也可以得分
对于subtask1,2,我们可以通过状压dp实现,状态表示那些点已经被取出,
表示在状态为
的情况下可以取出的最多白球数,可得到状态转移方程式,
。
其转移过程可以通过记忆化dp进行实现,这样的时间复杂度是,可以过掉前两个subtask。
对于subtask7,很容易发现,上面的做法,不算时间,光是空间都会炸,所以我们需要用map去维护dp值。但这样还是会T,考虑优化。我们发现,许多状态其实是重复的,因为根据他们得到剩余的序列是一样的。于是,我们考虑根据根据最后剩余的序列作为状态,来进行状态压缩。令表示剩余一个长度为
的序列,剩余球状态为
时可以得到的期望最大球数,状态转移方程式与上面的差不多。
可笔者还是会T on test subtask 32。因为map常数太大了,需要将其换成unordered_map,即使这样还是会T。
于是,我们还需要将状压dp数组拆成两端,一段状态数大的用map存,一段状态数小的用数组存,才卡得过去。
还是笔者常数太大了
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<tr1/unordered_map>
using namespace std;
using namespace tr1;
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,k;
unordered_map<int,double>F[10];
unordered_map<int,bool>Vis[10];
bool vis[22][(1<<21)+5];
double f[22][(1<<21)+5];
char maze[35];
double Max(double a,double b){return a>b?a:b;}
double dfs(int len,int S,int sum){
if(len>21){
if(Vis[len-21][S])return F[len-21][S];
//printf("%d %d %d\n",len,S,sum);
Vis[len-21][S]=1;if(len==n-k)return F[len-21][S]=1.0*sum;
double tmp=1.0/(1.0*len);
for(int i=1;i<=(len+1)/2;i++){
int t1=i,t2=len-i+1;
int S1=((S>>t1)<<t1-1)|(S&((1<<t1-1)-1)),s1=(S>>t1-1)&1;
int S2=((S>>t2)<<t2-1)|(S&((1<<t2-1)-1)),s2=(S>>t2-1)&1;
if(t1==t2)F[len-21][S]+=tmp*dfs(len-1,S1,sum+s1);
else F[len-21][S]+=2.0*tmp*Max(dfs(len-1,S1,sum+s1),dfs(len-1,S2,sum+s2));
}
//printf("%d %d:%lf\n",len,S,f[len][S]);
return F[len-21][S];
}
else{
if(vis[len][S])return f[len][S];
//printf("%d %d %d\n",len,S,sum);
vis[len][S]=1;if(len==n-k)return f[len][S]=1.0*sum;
double tmp=1.0/(1.0*len);
for(int i=1;i<=(len+1)/2;i++){
int t1=i,t2=len-i+1;
int S1=((S>>t1)<<t1-1)|(S&((1<<t1-1)-1)),s1=(S>>t1-1)&1;
int S2=((S>>t2)<<t2-1)|(S&((1<<t2-1)-1)),s2=(S>>t2-1)&1;
if(t1==t2)f[len][S]+=tmp*dfs(len-1,S1,sum+s1);
else f[len][S]+=2.0*tmp*Max(dfs(len-1,S1,sum+s1),dfs(len-1,S2,sum+s2));
}
//printf("%d %d:%lf\n",len,S,f[len][S]);
return f[len][S];
}
}
int main(){
//freopen("v.in","r",stdin);
//freopen("v.out","w",stdout);
read(n);read(k);scanf("\n%s",maze);
if(k==0){printf("%.7lf\n",0);return 0;}
if(k==n){
int sum=0;
for(int i=0;i<n;i++)sum+=(maze[i]=='W');
printf("%.7lf\n",1.0*sum);
return 0;
}
int sumW=0;
for(int i=0;i<n;i++)sumW+=(maze[i]=='W');
if(sumW==0){printf("%.7lf\n",0);return 0;}
if(sumW==n){printf("%.7lf\n",1.0*k);return 0;}
if(sumW==1){
double gl=1;
for(int i=0;i<k;i++){
int tmp=n-i;
gl*=1.0*(tmp-2)/tmp;
}
printf("%.7lf\n",1.0-gl);
return 0;
}
if(sumW==n-1){
printf("%.7lf\n",1.0*k);
return 0;
}
int num=0;
for(int i=0;i<n;i++)num<<=1,num|=(maze[i]=='W');
printf("%.7lf\n",dfs(n,num,0));
return 0;
}

浙公网安备 33010602011771号