2016-2017 ACM-ICPC, NEERC, Moscow Subregional Contest

K:

题意:王国里有n个城市通过m条双向边相连,每个城市可以花费bi去造一个士兵守护,然后每个城市需要ai个士兵守护。每条道路如果要守护,就必须要ci个士兵,这ci个士兵可以同时守护道路两端的城市。如果城市或者道路被守住了,那就可以免费运送士兵。问守住所有城市的最小花费。

思路:首先守边和守点求最小花费,最先想到的是树形DP的板题,只不过这是在一张图上,所以思路是一个DP。要考虑运兵的因素,,所以我们dp维护一个集合,表示守护这个集合的最小花费。集合之间的合并通过Kruskal。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <string>
#include <map>
using namespace std;

struct edge
{
    int u,v;
    long long num;
};
edge ed[300010];
int n,m;
long long ai[300010],bi[300010],sum[300010];
int fa[300010];

void init()
{
    for(int i=1;i<=n;i++) fa[i]=i;
}

bool cmp(const edge &a,const edge &b)
{
    return a.num<b.num;
}

int findfa(int x)
{
    if(fa[x]!=x) fa[x]=findfa(fa[x]);
    return fa[x];
}

int main()
{
    int i;
    scanf("%d%d",&n,&m);
    init();
    for(i=1;i<=n;i++)
    {
        scanf("%lld%lld",&ai[i],&bi[i]);
        sum[i]=ai[i]*bi[i];
    }
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&ed[i].u,&ed[i].v,&ed[i].num);
    }
    sort(ed+1,ed+1+m,cmp);
    for(i=1;i<=m;i++)
    {
        int u=findfa(ed[i].u),v=findfa(ed[i].v);
        if(u==v) continue;
        long long num=max(ai[u],max(ai[v],ed[i].num));
        long long cnt=min(bi[v],bi[u]);
        sum[u]=min(sum[v]+sum[u],cnt*num);
        fa[v]=u;
        ai[u]=num;
        bi[u]=cnt;
    }
    long long ans=0;
    for(i=1;i<=n;i++)
    {
        if(fa[i]==i) ans+=sum[i];
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

L:

题意:共有n给元素,有两种操作,一个是向容器里按顺序添加一个元素,一个是随机从容器里删除一个元素。现在给出2*n给操作序列以及每个操作的时间点。求每个元素在容器里的时间期望。

思路:发现如果两个元素留到了同一时刻,那么这两个元素将会等价。所以这就转换成了概率DP,从后往前处理,前一个元素在其后一个元素添加进来后和其后这个元素是等价的。然后只要计算其后一个元素添加进来之前的影响即可。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <stack>
using namespace std;
struct event
{
    char ch;
    double ti;
};
event ev[200010];
double dp[100010],ti[100010];
stack <event> st;
int n;
int main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=2*n;i++){
    getchar();
    scanf("%c%lf",&ev[i].ch,&ev[i].ti);
    }
    int sum=0,pos=n;
    dp[n+1]=0.0;
    for(i=2*n;i>0;i--){
    if(ev[i].ch=='-'){
        sum++;
        st.push(ev[i]);
    }
    else{
        ti[pos]=ev[i].ti;
        int num=sum;
        int cnt=0;
        while(!st.empty()){
        event now=st.top();
        st.pop();
        dp[pos]+=(now.ti-ti[pos])*(1/(double)(num));
        cnt++;
        }
        double p=1.0-(double)cnt/((double)num);
        dp[pos]+=(dp[pos+1]+ti[pos+1]-ti[pos])*p;
        pos--;
        sum--;
    }
    }
    for(i=1;i<=n;i++){
    printf("%.8lf\n",dp[i]);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Hetui/p/9169307.html