Codeforces Contest 1173 problem E1 Nauuo and Pictures (easy version) —— 记忆化+期望

202 篇文章 5 订阅
82 篇文章 1 订阅

This way

题意:

给你一些照片,每个照片有权重,还分是否喜欢,每次拿起一张照片,拿这张照片的概率是 wi/sum 如果喜欢这张照片,那么它的重量就会+1,否则-1,问你拿m次之后每张照片的权重是多少。

题解:

一直想不出来啊,每次我都是想着怎么去将所有的照片一起做掉,但是忘了数据范围很小,其实可以每个都做一遍,也就是n*m*m*m的时间复杂度,那么对于每个数,有3种情况:拿它,拿除它意外喜欢的照片,拿除它以外不喜欢的照片,由于喜欢和不喜欢是捆成一个整体的,所以拿哪一张都无所谓,那么这三个的集合就是候选键,接下来就是记忆化搜索了,val[i][j][k]表示当概率为dp[i][j][k]的时候拿了i次它本身,j次除它喜欢的,k次除它不喜欢的期望,那么期望=值*概率,所以在pos=0的时候即可返回,在vis[i][j][k]的时候,注意val[i][j][k]只是概率为dp[i][j][k]时的期望,不一定是当前期望,所以要转换为值,也就是*dp[i][j][k],再乘上概率再返回。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=998244353;
ll qpow(ll a,ll b)
{
    ll ans=1,ret=a;
    while(b)
    {
        if(b&1)
            ans=ans*ret%mod;
        ret=ret*ret%mod;
        b>>=1;
    }
    return ans;
}
ll dp[52][52][52],val[52][52][52],w[52];
int vis[52][52][52];
int f[52];
ll dfs(int pos,ll p,int i,int j,int k,ll na,ll nb,ll nc,int flag)
{
    if(!pos)
        return na*p%mod;
    if(vis[i][j][k])
        return qpow(dp[i][j][k],mod-2)*val[i][j][k]%mod*p%mod;
    dp[i][j][k]=p;
    val[i][j][k]+=dfs(pos-1,p*na%mod*qpow(na+nb+nc,mod-2)%mod,i+1,j,k,max(0ll,na+flag),nb,nc,flag);
    val[i][j][k]+=dfs(pos-1,p*nb%mod*qpow(na+nb+nc,mod-2)%mod,i,j+1,k,na,nb+1,nc,flag);
    val[i][j][k]+=dfs(pos-1,p*nc%mod*qpow(na+nb+nc,mod-2)%mod,i,j,k+1,na,nb,max(0ll,nc-1),flag);
    val[i][j][k]%=mod;
    vis[i][j][k]=1;
    return val[i][j][k];
}
int main()
{
    int n,m;
    ll like=0,dis=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&f[i]);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&w[i]);
        if(f[i])
            like+=w[i];
        else
            dis+=w[i];
    }
    ll ans;
    for(int i=1;i<=n;i++)
    {
        memset(dp,0,sizeof(dp));
        memset(val,0,sizeof(val));
        memset(vis,0,sizeof(vis));
        if(f[i])
            ans=dfs(m,1,0,0,0,w[i],like-w[i],dis,1);
        else
            ans=dfs(m,1,0,0,0,w[i],like,dis-w[i],-1);
        printf("%lld\n",ans);
    }
    printf("\n");
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值