zoukankan      html  css  js  c++  java
  • SCUT

    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: 
    ";
        /*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
    ",fdp(all1));
        }
    }
  • 相关阅读:
    delphi 随意将函数执行权限提高到Ring0源代码
    delphi 使电脑睡眠代码
    delphi 监控文件系统
    在Delphi中使用系统对应文件类型的图标
    Panel
    delphi 读写记录类型文件Record
    C# winform 一次只能允许一个应用(使用mutex)
    winform捕获全局异常
    观察者模式实践-实现winform 窗体之间传值(事件实现)
    在wpf中利用异步lambda编程,模拟数据库连接,防止界面假死
  • 原文地址:https://www.cnblogs.com/Yinku/p/10614324.html
Copyright © 2011-2022 走看看