码迷,mamicode.com
首页 > 其他好文 > 详细

1113

时间:2019-11-13 16:09:28      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:记录   需要   相同   --   efi   its   随机   等于   turn   

1.抓球
【问题描述】
何老板有N个不透明的箱子,编号1到N。每个箱子里都有若干大小相同的
小球,每个小球上都有一个编号。其中i号箱子里的小球编号是Xi到Yi,也就
是编号Xi,Xi+1,Xi+2,...,Yi-1,Yi的小球都在i号箱子里。
你需要从每个箱子里随机抓一个球出来, 从i号箱子抓出任意一个球的概
率都是1/(Yi-Xi+1)。如果你抓出的N个球中,有大于等于S%的球的编号第一
位都是1(比如: 15, 138, 1196的第一位都是1),那么你将赢得一次与何老
板共进午餐的机会。
问,你赢得美妙午餐的概率有多大?

解:
由于没开LL 掉40....
DP一下即可
code:

//
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define GC getchar()
#define D double
#define maxnn 2100
ll sum[maxnn];
ll n,s;
D f[maxnn][maxnn];
ll res[maxnn];
ll xx[maxnn],yy[maxnn];
double ans=0;
inline ll R() {
    char t;
    int f=1;
    ll x=0;
    t=GC;
    while(!isdigit(t)) {
        if(t=='-') f=-1;
        t=GC;
    }
    while(isdigit(t)) {
        x=x*10+t-48;
        t=GC;
    }
    return x*f;
}

int main() {
    sum[1]=1;
    for(int i=2; i<=20; i++) {
        sum[i]=sum[i-1]*10;
    }
    for(int i=2; i<=20; i++) {
        sum[i]=sum[i-1]+sum[i];
    }
    n=R();
    s=R();
    ll x,y;
    for(int i=1; i<=n; i++) {
        x=R();
        xx[i]=x;
        y=R();
        yy[i]=y;
        x--;
        string s1,s2;
        while(x) {
            s1.push_back((x%10)+48);
            x/=10;
        }
        ll tmp1=0;
        if(s1.back()!='1') {
            tmp1+=sum[s1.size()];
        } else {
            ll remake1=0;
            for(int k=s1.size()-2; k>=0; k--) {
                remake1=(remake1*10+s1[k]-'0');
            }
            tmp1+=sum[s1.size()-1]+remake1+1;
        }
        while(y) {
            s2.push_back((y%10)+48);
            y/=10;
        }
        ll tmp2=0;
        if(s2.back()!='1') {
            tmp2+=sum[s2.size()];
        } else {
            ll remake2=0;
            for(int k=s2.size()-2; k>=0; k--) {
                remake2=(remake2*10+s2[k]-'0');
            }
            tmp2+=sum[s2.size()-1]+remake2+1;
        }
        res[i]=tmp2-tmp1;
    }
    f[0][0]=1.0;
    for(int i=1; i<=n; i++) {
        for(int j=0; j<=i; j++) {
            if(j==0) {
                f[i][j]=f[i-1][j]*((yy[i]-xx[i]+1-res[i])/1.0/(yy[i]-xx[i]+1));
            } else {
                f[i][j]=f[i-1][j-1]*(res[i]/1.0/(yy[i]-xx[i]+1))+f[i-1][j]*(((yy[i]-xx[i]+1)-res[i])/1.0/(yy[i]-xx[i]+1));
            }
        }
    }
    for(int i=(ceil(n*(s/1.0/100))); i<=n; i++) {
        ans+=f[n][i];
    }
    printf("%.7lf",ans);
}

B
【问题描述】
游戏LOL中的召唤师峡谷地图是一个有n个节点, m条单向道路构成的。最
近,游戏推出了一个新英雄,他拥有特殊技能,对于峡谷中的任意一个节点
x,可以把所有以x为终点的边的权值减少d,同时把所有以x为起点的边的权值
加上d。 现在我们操控新英雄使用他的技能,让所有边的权值的最小值最大。
边的权值>0。
解:
二分+差分约束
看到infinite 我想多了
超过就是infinite...
二分答案跑负环即可
code;

/
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define maxnn 6000
#define inf 1000000000
int dis[maxnn];
int n ,m;
int las[maxnn],en[maxnn],nex[maxnn],tot,le[maxnn];
void add(int a,int b,int c) {
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
    le[tot]=c;
}
int mapp1[maxnn][maxnn];
#define GC getchar()
inline int R() {
    char t;
    int f=1;
    int x=0;
    t=GC;
    while(!isdigit(t)) {
        if(t=='-') f=-1;
        t=GC;
    }
    while(isdigit(t)) {
        x=x*10+t-48;
        t=GC;
    }
    return x*f;
}
int cnt[maxnn];
int mark[maxnn];
int fla=1;
bool spfa(int x,int mid)
{
    for(int i=las[x];i;i=nex[i])
    {
        int v=en[i];
        if(dis[v]>dis[x]+le[i]-mid)
        {
            dis[v]=dis[x]+le[i]-mid;
            if(mark[v])return false;
            mark[v]=1;
            if(!spfa(v,mid))return false;
        }
    }
    mark[x]=0;
    return true;
}
  

bool isok(int mid) {
    for(int i=0;i<=n;i++)
    {
        mark[i]=0;  
        dis[i]=inf;
    }
    dis[0]=0;
    mark[0]=1;
    if(!spfa(0,mid))
     return false;
    return true;
}
int main() {
    while(cin>>n>>m) {
        int a,b,c;
        memset(las,0,sizeof(las));
        tot=0;
        for(int i=1; i<=m; i++) {
            a=R();
            b=R();
            c=R();
            add(a,b,c);
        }
        for(int i=1; i<=n; i++) {
            add(0,i,0);
        }
        int l=0,r=110100;
        while(l<=r) {
            int mid=(l+r)>>1;
            if(isok(mid)) {
                l=mid+1;
            } else {
                r=mid-1;
            }
        }
        if(l>10000) {
            {
                printf("Infinite\n");
                continue;
            }
        }
        if(l==0) {
            printf("No Solution\n");
            continue;
        }
        printf("%d\n",r);
        continue;
    }
    return 0;
}

C 攻略
时间限制 : - MS 空间限制 : - KB
评测说明 : 1s,128m
问题描述
题目简述:树版[k取方格数]
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状
结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的) “为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”
解:
长链剖分
考试的时候我居然以为这个东西有后效性..... 然而没有...
或者树形DP记录是哪个儿子传给的 扔进堆里面就行了每次找的时候 更新就行了 ...
或者线段树+dfs序列
记录树上前缀和
每次查找的时候找最长的
然后往上减 去掉子树的影响就行了
code:

//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 400010
#define ll long long 
ll las[maxnn],en[maxnn],nex[maxnn],tot;
ll a[maxnn];
ll n,m;
struct node {
    ll st,en,l;
};
bool operator <(node a,node b) {
    return a.l<b.l;
}
priority_queue<node> Q;
ll ff[maxnn];
#define GC getchar()
inline ll R() {
    char t;
    int f=1;
    ll x=0;
    t=GC;
    while(!isdigit(t)) {
        if(t=='-') f=-1;
        t=GC;
    }
    while(isdigit(t)) {
        x=x*10+t-48;
        t=GC;
    }
    return x*f;
}
void add(int a,int b) {
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
}
ll f[maxnn],id[maxnn];
void DP(int v,int fa) {
    ff[v]=fa;
    for(int i=las[v]; i; i=nex[i]) {
        int u=en[i];
        if(u==fa) continue;
        DP(u,v);
        if(f[u]>f[v]) {
            f[v]=f[u];
            id[v]=id[u];
        }
    }
    if(id[v]==0) {
        id[v]=v;
    }
    f[v]+=a[v];
}
int main() {

    n=R();
    m=R();
    for(int i=1; i<=n; i++) {
        a[i]=R();
    }
    int x,y;
    for(int i=1; i<n; i++) {
        x=R();
        y=R();
        add(x,y);
        add(y,x);
    }
    DP(1,1);
    for(int i=las[1]; i; i=nex[i]) {
        int u=en[i];
        Q.push(node {u,id[u],f[u]});
    }
    ll ans=0;
    while(m--) {
        ans+=Q.top().l;
        node r=Q.top();
        int d=r.en;
        int pos;
        pos=d;
        while(d!=ff[r.st]) {
            for(int i=las[d]; i; i=nex[i]) {
                int u=en[i];
                if(u==pos) continue;
                if(u==ff[d]) continue;
                Q.push(node{u,id[u],f[u]});
            }
            pos=d;
            d=ff[d];
        }
        Q.pop();
    }
    cout<<ans+a[1];
}

长链剖分:
贪心地选取代价最大的链

//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 400010
#define ll long long
ll las[maxnn],en[maxnn],nex[maxnn],tot;
ll a[maxnn];
ll n,m;
priority_queue<ll> Q;
ll ff[maxnn];
#define GC getchar()
inline ll R() {
    char t;
    int f=1;
    ll x=0;
    t=GC;
    while(!isdigit(t)) {
        if(t=='-') f=-1;
        t=GC;
    }
    while(isdigit(t)) {
        x=x*10+t-48;
        t=GC;
    }
    return x*f;
}
void add(int a,int b) {
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
}
ll f[maxnn],id[maxnn];
ll son[maxnn];
int topp[maxnn];

void dfs1(int v,int fa) {
    for(int i=las[v]; i; i=nex[i]) {
        int u=en[i];
        if(u!=fa) {
            dfs1(u,v);
            if(f[u]>f[v]) {
                f[v]=f[u];
                son[v]=u;
            }

        }

    }
    f[v]+=a[v];
}
void dfs2(int v,int fa,int t) {
    topp[v]=t;
    if(son[v]) {
        dfs2(son[v],v,t);
    }
    for(int i=las[v]; i; i=nex[i]) {
        int u=en[i];
        if(u==son[v]) continue;
        if(u!=fa) {
            dfs2(u,v,u);
        }
    }
}
int main() {
    
    n=R();
    m=R();
    for(int i=1; i<=n; i++) {
        a[i]=R();
    }
    int x,y;
    for(int i=1; i<n; i++) {
        x=R();
        y=R();
        add(x,y);
        add(y,x);
    }
    dfs1(1,1);
    ll ans=0;
    dfs2(1,1,1);
    for(int i=1; i<=n; i++) {
        if(topp[i]==i) {
            Q.push(f[i]);
        }
    }
    while(m--) {
        ans+=Q.top();
        Q.pop();
    }
    cout<<ans;
}

1113

标签:记录   需要   相同   --   efi   its   随机   等于   turn   

原文地址:https://www.cnblogs.com/OIEREDSION/p/11849741.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!