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; }
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; }