SCUT - 254 - 欧洲爆破 - 概率dp - 状压dp

Posted yinku

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SCUT - 254 - 欧洲爆破 - 概率dp - 状压dp相关的知识,希望对你有一定的参考价值。

https://scut.online/p/254

思路很清晰,写起来很恶心。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int dp[1<<20];
//dp[k] 从状态k开始直到k=0还需要的期望次数 0表示炸弹已爆炸,1表示炸弹未爆炸
int x[20];
int y[20];
int r[20];

int pa[20];

ll n;
ll invn;
int all1;

int vis[20];

bool canboom(int id,int id2){
    return (1ll*r[id]*r[id])>=(1ll*(x[id]-x[id2])*(x[id]-x[id2])+1ll*(y[id]-y[id2])*(y[id]-y[id2]));
}

void dfs(int id){
    vis[id]=1;
    for(int i=0;i<n;i++){
        if(vis[i]==0&&(canboom(id,i))){
            dfs(i);
        }
    }
}

void find_pa(int id){
    memset(vis,0,sizeof(vis));

    dfs(id);
    //把自己引爆;

    //cerr<<"boom:"<<id<<" can boom: \n";
    /*for(int i=0;i<n;i++){
        cerr<<vis[i];
    }
    cout<<endl;*/

    int ans=all1;
    //假设所有炸弹都能被引爆
    for(int i=0;i<n;i++){
        if(vis[i]){
            //从左往右的第i个不能被引爆
            //0 1 2 3
            //二进制的低位都是在右边
            //3 2 1 0
            ans&=(~(1<<i));
            //&=1110111设为0,该炸弹不能被引爆
            //cout<<bitset<3>(~(1<<(n-1-i)))<<endl;
        }

    }
    //cout<<bitset<3>(ans)<</*"!"<<*/endl;
    pa[id]=ans;
}

int p=1000000009;

//快速幂 x^n%p
ll qpow(ll x,ll n) {
    ll res=1;
    while(n) {
        if(n&1)
            res=res*x%p;
        x=x*x%p;
        n>>=1;
    }
    return res%p;
    //要记得模p,否则输入一个2的幂次模1就挂了
}


//乘法逆元 快速幂+费马小定理 模必须是质数
ll inv(ll n) {
    return qpow(n,p-2);
}

int count0(int k){
    int cnt=0;
    for(int i=0;i<n;i++){
        if(!(k&1))
            cnt++;
        k>>=1;
    }
    return cnt;
}

int fdp(int k){
    //cout<<"[fdp]="<<" "<<bitset<3>(k)<<endl;
    if(dp[k]!=-1){
        //cerr<<" dp["<<k<<"]="<<dp[k]<<endl;
        return dp[k];
    }

    int cnt0=count0(k);

    //cout<<"k="<<k<<" cnt0="<<cnt0<<endl;
    ll ans=0;

    for(int i=0;i<n;i++){
        if(k&(1<<i)){
            //cout<<"i="<<i<<endl;
            //k的右起第i位,第i个炸弹没被引爆
            int can=pa[i];
            //第i个炸弹把can为1的这些都引爆,也就是把can为1的设成0
            //cout<<"can="<< bitset<3>(can)<<endl;
            ans+=(fdp(k&(can)))*invn;
            //cerr<<" tmp ans="<<ans<<endl;
            ans%=p;
        }
    }

    ans+=1;
    ans%=p;

    //cerr<<" tmp dp["<<k<<"]="<<ans<<endl;

    ans*=n;
    ans%=p;

    ans*=inv(n-cnt0);
    ans%=p;
    //cerr<<" dp["<<k<<"]="<<ans<<endl;
    return dp[k]=ans;
}

int main(){
    //cout<<"inv2="<<inv(2)<<endl;
    while(~scanf("%lld",&n)){
        invn=inv(n);

        for(int i=0;i<n;i++){
            scanf("%d%d%d",x+i,y+i,r+i);
        }

        all1=0;
        for(int i=0;i<n;i++){
            all1<<=1;
            all1|=1;
        }

        for(int i=0;i<n;i++){
            //cerr<<"!";
            find_pa(i);
        }

        memset(dp,-1,sizeof(dp));

        dp[0]=0;//所有炸弹都爆炸了

        //求dp[all1]

        //cout<<bitset<3>(all1)<<endl;

        printf("%d\n",fdp(all1));
    }
}

 

以上是关于SCUT - 254 - 欧洲爆破 - 概率dp - 状压dp的主要内容,如果未能解决你的问题,请参考以下文章

scut 125. 笔芯回文

SCUT - 249 - Hello World - 数位dp

SCUT - 289 - 小O的数字 - 数位dp

SCUT 125 :笔芯回文(DP)

炉石传说 疯狂爆破者空场炸死2个精灵龙的概率

[BZOJ 4008][HNOI2015]亚瑟王(期望Dp)