1213D1,1364C,POJ 2096,POJ 3744,ZOJ 3329

78 阅读2分钟

1213D1 - Equalizing by Division (easy version)

 n才50,a[i]才2e5,让求至少k个相等的数,那我们就直接枚举i=0-2e5看看变成k个i最小的花费次数就可以了

ll n,k,a[55];
int main(){
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    ll ans=1e18;
    for(int i=0;i<=200005;i++){
            ll res=0,cnt=0;
        for(int j=1;j<=n;j++){
            if(cnt>=k) break;
            ll x=a[j],sum=0;
            while(x>i){
                x/=2;
                sum++;
            }
            if(x==i) res+=sum,cnt++;
        }
        if(cnt>=k) ans=min(ans,res);
    }
    printf("%lld\n",ans);
    return 0;
}

1364C - Ehab and Prefix MEXs 构造

在这题上浪费了两个半小时,,,自己想的思路都没有过掉,最后想的一个也在第21个样例上T掉了,,,a[i]一定是递增的所以b[i]=a[i-1]是一定不会错的,另外就是要注意a[i]==a[i-1]的时候,一直到a[j]!=a[i],b[j]的值一定是等于a[i]的,相等的那些值就尽量用小数来填,不能用后面出现的数

Ehab and Prefix MEXs_逍遥Fau的博客-CSDN博客

ll n,a[100005],b[100005],vis[100005];
vector<ll>v;
int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),vis[a[i]]=1;
    for(int i=1;i<=100000;i++)
        if(!vis[i]) v.push_back(i);
    ll ind=0;
    for(int i=1;i<=n;i++){
        if(a[i]==a[i-1]) b[i]=v[ind++];
        else b[i]=a[i-1];
        printf("%lld ",b[i]);
    }
    return 0;
}

Collecting Bugs - POJ 2096 - Virtual Judge (vjudge.net) 概率dp

设dp[i][j]为已经找到i种bug,j个子系统有bug所需要的天数的期望,则可以有dp[i-1][j],dp[i][j],dp[i][j-1],dp[i-1][j-1]四种情况转移下来,发现dp[i][j]是可以通过自身转移的,移项就可以,移完项后发现在i==n&&j==s的情况下分母是0,所以应该倒着枚举,状态就变为设dp[i][j]为还需要找到i种bug,j个子系统有bug所需要的天数的期望,那么初始状态就是dp[n][s]=0,dp[0][0]是答案,这题的难点就在于dp[n][s]要设为初始状态,我一开始以为dp[0][0]也是可以作为初始状态的,但是一直不对,最后发现i==n j==s时也是一样需要移项的,所以避免不了除0的情况,所以只能倒着枚举

ll n,s;
double dp[1005][1005];
int main(){
    while(scanf("%lld%lld",&n,&s)!=EOF){
        dp[n][s]=0;
        for(int i=n;i>=0;i--)
        for(int j=s;j>=0;j--){
            if(i==n&&j==s) continue;
            dp[i][j]=((n-i)*j*dp[i+1][j]+i*(s-j)*dp[i][j+1]+(n-i)*(s-j)*dp[i+1][j+1]+n*s)/(n*s-i*j);
        }
    printf("%.4f",dp[0][0]);
    }
    return 0;
}

Scout YYF I - POJ 3744 - Virtual Judge (vjudge.net) 概率dp

设dp[i]为走到第i步是安全的概率,dp[i]=p*dp[i-1]+(1-p)*dp[i-2],1e8太大,所以考虑矩阵快速幂(快速求递推式用的),将路分成多个段根据给出的a[i],算出a[i]--a[i-1]这一段之后将第a[i]步的概率变为0,也就是代码中求下一段之前先把ans.mat[0][0]=0,注意第一段的时候还需要ans.mat[0][0]=1,因为是从第一步开始的,答案就是a[n]-1的概率乘以(1-p)

int mod=1e7+7;
double eps=1e-8;
struct matrix{
    double mat[2][2];
    matrix operator*(matrix const &b)const{
        matrix res;
        memset(res.mat,0,sizeof(res.mat));
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
            res.mat[i][j]=(res.mat[i][j]+this->mat[i][k]*b.mat[k][j]);
        return res;
    }
};
matrix matpow(matrix a,ll b){
    matrix res;res.mat[0][0]=res.mat[1][1]=1;
    res.mat[0][1]=res.mat[1][0]=0;
    while(b){
        if(b&1) res=a*res;
        a=a*a;
        b>>=1;
    }
    return res;
}
ll n,a[15];
double p;
int main(){
    while(scanf("%lld%lf",&n,&p)!=EOF){
         for(int i=1;i<=n;i++) scanf("%lld",&a[i]);a[0]=1;
         matrix res,ans,b;
         b.mat[0][0]=p;b.mat[0][1]=1-p;b.mat[1][0]=1;b.mat[1][1]=0;
         sort(a+1,a+n+1);
         for(int i=1;i<=n;i++){
            ll x=a[i]-a[i-1];
            res=matpow(b,x);
            //cout<<res.mat[0][0]<<" "<<res.mat[0][1]<<" "<<res.mat[1][0]<<" "<<res.mat[1][1]<<endl;
            //cout<<b.mat[0][0]<<" "<<b.mat[0][1]<<" "<<b.mat[1][0]<<" "<<b.mat[1][1]<<endl;
            if(i==1){
                ans.mat[0][0]=1;
                ans.mat[0][1]=ans.mat[1][0]=ans.mat[1][1]=0;
            }
            else ans.mat[0][0]=0;
            ans=res*ans;
           // cout<<ans.mat[0][0]<<" "<<ans.mat[1][0]<<" "<<i<<endl;
         }
         double asw=ans.mat[1][0]*(1-p);
         printf("%.7f\n",asw);
    }
    return 0;
}

One Person Game - ZOJ 3329 - Virtual Judge (vjudge.net) 概率dp

设dp[i]为分数到达i时的期望,大于n的情况太多了,但是我们可以倒着推,这样dp[0]就是答案了,

dp[i]=(dp[i+k]*pk)+dp[0]p0+1,pk为得分为k使得概率,p0在这里为抽到a,b,c的概率,也代表抽到任意一种情况的概率,假设dp[i]=x[i]dp[0]+y[i],则带入上面的方程可以求出x[i]=sum(pkx[i+k])+p0,y[i]=sum(pky[i+k])+p0,答案就是y[0]/(1-x[0])

【原创】概率DP总结 by kuangbin - kuangbin - 博客园 (cnblogs.com)

ll t,n,k1,k2,k3,a,b,c;
double x[505],y[505],p[55];
int main(){
    scanf("%lld",&t);
    while(t--){
        cin>>n>>k1>>k2>>k3>>a>>b>>c;
        memset(p,0,sizeof(p));
        double p0=1.0/k1/k2/k3;
        for(int i=1;i<=k1;i++)
            for(int j=1;j<=k2;j++)
            for(int k=1;k<=k3;k++)
            if(i!=a||j!=b||k!=c) p[i+j+k]+=p0;
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        for(int i=n;i>=0;i--){
            x[i]=p0;y[i]=1;
            for(int j=1;j<=k1+k2+k3;j++)
                x[i]+=p[j]*x[i+j],y[i]+=p[j]*y[i+j];
        }
        double ans=y[0]/(1-x[0]);
        printf("%.16f\n",ans);
    }
    return 0;
}