• 1113


    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
    ");
    				continue;
    			}
    		}
    		if(l==0) {
    			printf("No Solution
    ");
    			continue;
    		}
    		printf("%d
    ",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;
    }
    
  • 相关阅读:
    东边日出西边雨
    ZooKeeper学习(一)了解ZooKeeper
    linux学习(七)文件打包和压缩命令
    linux学习(六)Linux yum 命令
    linux学习(五)Linux 文件与目录管理
    linux学习(四)Linux 文件基本属性
    linux学习(三)Linux 系统目录结构
    linux学习(二)认识Linux
    linux学习(一)认识阿里云
    多线程实战【面试题形式】
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11849741.html
Copyright © 2020-2023  润新知