矿石采集(计蒜客信息学3月提高组模拟赛)

矿石采集(计蒜客信息学3月提高组模拟赛)

题目描述

传送门

思路

这题首先,题意要看懂。。。。

可以将问题分为几个子问题

  • 所有询问从起点到终点能获得的最大矿物价值。
  • 选取若干个时间区间不相交的询问,使得按题意要求算到的期望值最大。

对于第一个子问题,比较简单,预处理一下拥有哪几种矿石时的总价值。然后对整个图用\(tarjan\)强连通缩点。单个点的矿石状态为包含的点的或和。然后以每个点为起点跑一边\(bfs\)\(dfs\)即可,最终求出每个询问的最优价值\(v_i\)

对于第二个子问题,对于时间区间不相交处理较简单,很套路,排序一维,数据结构(树状数组etc)维护另一维。

然后就是难点,算期望。经过一系列的推导可以得到如下结论:

\(f[i]\)表示以\(i\)为执行任务的起点,能得到的最大起点,有:

\[f[j]=(1-p_j)*f[i]+(1-p_j)*v_j-c_j \]

有了这个,我们就可以按每个任务起点时间从大到小进行转移了。最终复杂度\(O(n^{2..3}+nlog_n)\)

code

#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=(l),i##R=(r);i<=i##R;i++)
#define DOR(i,r,l) for(int i=(r),i##L=(l);i>=i##L;i--)
#define loop(i,n) for(int i=0,i##R=(n);i<i##R;i++)
#define mms(a,x) memset(a,x,sizeof a)
#define pb push_back
#define pii pair<int,int>
#define X first
#define Y second
using namespace std;
typedef long long ll;
typedef double db;
template<typename A,typename B>inline void chkmax(A &x,const B y){if(x<y)x=y;}
template<typename A,typename B>inline void chkmin(A &x,const B y){if(x>y)x=y;}
const int N=1e5+5,M=220,inf=1e9;
int n,m,K,q; 
int mi[M],w[M];
char s[15];
struct Graph{
	int tot,to[M],nxt[M],head[M];
	void add(int x,int y){tot++;to[tot]=y;nxt[tot]=head[x];head[x]=tot;}
	void clear(){mms(head,-1);tot=0;}
	#define EOR(G,i,x) for(int i=G.head[x];i!=-1;i=G.nxt[i])
}G,T;
struct Query{
	int s,t,c,l,r;
	db p;
	int val;
	bool operator<(const Query &A)const{
		return l>A.l;
	}
}Q[N];
int b[N<<1],h;
int rev[1050];
int dfn[M],low[M],bel[M],cnt,tot;
int stk[M],tp,stat[M];
void tarjan(int x){
	low[x]=dfn[x]=++tot;
	stk[++tp]=x;
	EOR(G,i,x){
		int v=G.to[i];
		if(!dfn[v]){
			tarjan(v);
			chkmin(low[x],low[v]);
		}else if(!bel[v])chkmin(low[x],dfn[v]);
	}
	if(dfn[x]==low[x]){
		int t;cnt++;
		do {
			bel[t=stk[tp--]]=cnt;
			stat[cnt]|=mi[t];
		}while(t!=x);
	}
}
bool link[M][M];
void construct(){
	FOR(x,1,n)EOR(G,i,x){
		int v=G.to[i];
		link[bel[x]][bel[v]]=1;
	}
}
int vis[M][1050],ti;
int mxv[M];
int dis[M][M];
void dfs(int x,int S){
	if(vis[x][S]==ti)return;
	vis[x][S]=ti;
	chkmax(mxv[x],rev[S]);
	FOR(v,1,cnt)if(link[x][v])
		dfs(v,S|stat[v]);
}
void init_val(){
	loop(i,1<<K)loop(j,K)if(i>>j&1)rev[i]+=w[j];
	FOR(i,1,n)if(!dfn[i])tarjan(i);
	construct();
	FOR(i,1,cnt){
		FOR(j,1,cnt)mxv[j]=-inf;
		ti=i,dfs(i,stat[i]);
		FOR(j,1,cnt)dis[i][j]=mxv[j];
	}
	loop(i,q)Q[i].val=dis[bel[Q[i].s]][bel[Q[i].t]];
}
void init_Interval(){
	h=0;
	loop(i,q)b[++h]=Q[i].l,b[++h]=Q[i].r;
	sort(b+1,b+h+1);
	h=unique(b+1,b+h+1)-b-1;
	loop(i,q){
		Q[i].l=lower_bound(b+1,b+h+1,Q[i].l)-b;
		Q[i].r=lower_bound(b+1,b+h+1,Q[i].r)-b;
	}
}
struct Binary_Indexed_Tree{
	#define lowbit(x) (x&(-x))
	db c[N<<1];
	void update(int x,db val){while(x)chkmax(c[x],val),x-=lowbit(x);}
	db query(int x){db ret=0;while(x<(N<<1))chkmax(ret,c[x]),x+=lowbit(x);return ret;}
}BIT;
int main(){
	scanf("%d%d%d%d",&n,&m,&K,&q);
	FOR(i,1,n){
		scanf("%s",s);
		loop(j,strlen(s))mi[i]|=((s[j]-'0')<<j);
	}
	G.clear();
	FOR(i,1,m){
		int x,y;scanf("%d%d",&x,&y);
		G.add(x,y);
	}
	loop(i,K)scanf("%d",&w[i]);
	loop(i,q){
		scanf("%d%d%d%lf%d%d",&Q[i].l,&Q[i].s,&Q[i].t,&Q[i].p,&Q[i].c,&Q[i].r);
		Q[i].r+=Q[i].l;
	}
	init_val();
	init_Interval();
	sort(Q,Q+q);
	db ans=0;
	loop(i,q){
		db Val=BIT.query(Q[i].r);
		Val=(Val+Q[i].val)*(1.0-Q[i].p)-1.0*Q[i].c;
		chkmax(ans,Val);
		BIT.update(Q[i].l,Val);
	}
	printf("%.6lf\n",ans);
	return 0;
}
posted @ 2019-09-01 19:30  Hëinz  阅读(197)  评论(0编辑  收藏  举报