zoukankan      html  css  js  c++  java
  • 2021.09.05 膜你赛

    2021.09.05 膜你赛

    T1 game

    Description

    \(Ariel\) 最近去参加了一个锦标赛,这个锦标赛总共有 \(n\) 轮比赛,最终成绩由这 \(n\) 轮比赛中赢的轮数决定。对于 \(Ariel\) 每一轮比赛的胜利概率,则取决于他在该轮比赛之前的战绩。也就是说,如果 \(Ariel\) 在第 \(i\) 轮比赛选择积极应战,并且前 \(i-1\) 轮比赛中取得了 \(j\) 胜的话,那么第 \(i\) 轮比赛的胜率概率为 \(p[i][j]\),这里我们保证了一点就是对于同一个 \(i\)\(p[i][j]\) 关于 \(j\) 的上升保持单调不上升(也就是说 \(p[i][j] \geq p[i][j+1])\)

    \(Ariel\) 观察到这个规则之后,想到了一个可能可以使他最终成绩更优的方法,就是在某些轮比赛采取第二种策略,故意求败,也就是以 \(100\%\) 的概率输掉该轮比赛,从而使自己在后面能够遇到更容易对付的对手。

    \(Ariel\) 现在已经看到了整个 \(p\) 数组,希望你能告诉他一个最优的策略,使得他能最大化他的期望赢的轮数。这里,定义一下期望。假如我们要求一个事件 \(A\) 的期望,那么假如事件 \(A\)\(P_i\) 的概率结果为 \(i\),那么事件 \(A\)
    的期望则是 \(i\times P_i\) 的和,大概的含义就是结果值关于概率的一个加权平均数。

    Solution

    不明白怎么做最优决策,于是直接根据样例莽上去的概率期望dp。

    \(f_{i,j}\) 表示当前在第 \(i\) 轮,赢 \(j\) 轮的概率。

    \(f_{i,j}=f_{i-1,j}\times(i-p_{i,j})+f_{i-1,j-1}\times p_{i,j-1}\)

    最后答案为 \(\sum\limits_{i=1}^n i\cdot f_{n,i}\)

    /*
    * @Author: smyslenny
    * @Date:    2021.09.
    * @Title:   
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=998244353;
    const int M=1e3+5;
    int n;
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    double p[M][M],f[M][M];
    namespace substack1{
    	double Ans;
    	void main()
    	{
    		if(n==1) printf("%.2lf\n",p[1][0]);
    		else
    		{
    			Ans+=(1-p[1][0])*(1-p[2][0])*0+(1-p[1][0])*p[2][0]+p[1][0]*(1-p[2][1])+p[1][0]*p[2][1]*2;
    			printf("%.2lf\n",Ans);
    		}
    	}
    }
    namespace substack2{
    	double Ans;
    	void main()
    	{
    		f[0][0]=1; 
    		for(int i=1;i<=n;i++)
    			for(int j=0;j<=i;j++)
    				f[i][j]+=(j<i)?f[i-1][j]*(1-p[i][j]):0.0,//这轮没连续赢,才有输的概率 
    				f[i][j]+=(j>0)?f[i-1][j-1]*p[i][j-1]:0.0;//这轮没连续输,才有赢的概率 
    		for(int i=0;i<=n;i++)
    			Ans+=f[n][i]*i;
    		printf("%.2lf",Ans);
    	}
    }
    
    int main()
    {
    //	freopen("game.in","r",stdin);
    //	freopen("game.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    		for(int j=0;j<i;j++)
    			scanf("%lf",&p[i][j]);
    	if(n<=2) substack1::main();
    	else substack2::main();
    	return 0;
    }
    
    /*
    2
    0.5
    0.5 0.5
    2
    0.5
    0.4 0.3
    */
    

    T2

    Description

    双十一就要来啦!\(YCC\) 刚刚获得了一笔 \(X\) 元的奖金。那么是不是应该清空下购物车呢?

    购物车总共有 \(N\) 个物品,每个物品的价格为 \(V_i\)\(YCC\) 想尽可能地把手头的奖金给花光,所以她要精新选择一些商品,使得其价格总和最接近但又不会超过奖金的金额。那么 \(YCC\) 最后最少可以剩下多少钱呢?

    Solution

    一开始写的dp,先造了几组数据发现没问题,然后就去做别的题了,后来写了暴力去拍发现写假了,想不出怎么改,交上去了暴力,发现只要加一句剪枝就过了。

    Code

    /*
    * @Author: smyslenny
    * @Date:    2021.09.05
    * @Title:   cake
    * @Main idea:dp
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define int long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=998244353;
    const int M=1e3+5;
    int n,V,v[M];
    int f[M][3];
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    
    bool cmp(int a,int b)
    {
    	return a>b;
    }
    int js,Ans,fg;
    
    namespace substack2{
    
    	void main()
    	{ 
    		sort(v+1,v+1+n,cmp);
    		if(v[1]<=V) f[1][1]=v[1];
    		else f[1][1]=0;
    		f[1][0]=0;
    		for(int i=2;i<=n;i++)
    		{
    			f[i][0]=max(f[i-1][0],f[i-1][1]);
    			if(f[i-1][0]+v[i]<=V)
    				f[i][1]=max(f[i][1],f[i-1][0]+v[i]);
    			if(f[i-1][1]+v[i]<=V)
    				f[i][1]=max(f[i][1],f[i-1][1]+v[i]);
    		}
    		printf("%lld\n",V-max(f[n][0],f[n][1]));
    	}
    }
    namespace substack1
    {
    	void dfs(int x)
    	{
    //		if(fg) return;
    //		if(js<0) {fg=1;return;}
    
    		if(js>V) return;
    		if(x>n) return; 
    		if(js+v[x]<=V)
    		{
    			js+=v[x];
    			Ans=max(Ans,js);
    			dfs(x+1);
    			js-=v[x];
    		}
    		dfs(x+1);
    	}	
    	void main()
    	{
    		if(n>1000)
    			substack2::main();
    		else 
    		{
    			dfs(1);
    			printf("%lld\n",V-Ans);
    		}
    	}
    }
    namespace substack3{
    	int sum[M],Ans;
    	void dfs(int x)
    	{
    		if(js+sum[x]<Ans) return;
    		if(js>V) return;
    		if(x>n) return;
    		if(js+v[x]<=V)
    		{
    			js+=v[x];
    			Ans=max(Ans,js);
    			dfs(x+1);
    			js-=v[x];
    		}
    		dfs(x+1);
    		return;
    	}
    	void main()
    	{
    		sort(v+1,v+1+n,cmp);
    		for(int i=n;i>=1;i--) sum[i]=sum[i+1]+v[i];
    		dfs(1);
    		printf("%lld\n",V-Ans);
    	}
    }
    
    signed main()
    {
    //	freopen("cake.in","r",stdin);
    //	freopen("cake.out","w",stdout);
    	n=read(),V=read();
    	for(int i=1;i<=n;i++)
    		v[i]=read();
    	substack1::main();
    	return 0;
    }
    /*
    6 2000
    200 700 600 1900 300 400
    */		
    
    

    T3

    Description

    现在轮到 \(BS\) 给这题造数据了,但他又不会写这题的标程,于是对于每个询问他都先随机出一个答案,接着想通过答案去构造出一个满足所有答案的数据。换句话说,对于构造出来的矩阵,对于每次询问的子矩阵,其中的最大值需要等于 \(BS\) 预先设定的答案。

    现在 \(BS\) 已经预先设定好答案了,那么满足要求的矩阵到底有多少个呢?

    Solution

    对于一个点来说,他能做出贡献的只有覆盖在它上面的需要的最大值最小的矩形,易知对于只有一个矩形的图,答案为 \((m^{cnt}-(m-1)^{cnt})\times m^{k\times m-cnt}\) ,然后因为矩形之后十个,对于每个点,存一个十位的状态表示他对这些矩形是否做出贡献,对一个矩形,强制让这个点做贡献+非强制做贡献,dp一下,但是 $w\times h $ 个点非常大,考虑离散化。
    好像没过,以后再改吧。

    Code

    /*
    * @Author: smyslenny
    * @Date:    2021.09.05
    * @Title:   
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=1e9+7;
    const int M=1e3+5;
    int T,n,m,h,w;
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    int qx[M],x,qy[M],y,Ans,f[M][M];
    struct node{
    	int x_1,y_1,x_2,y_2,v;
    }sz[M];
    int qpow(int a,int b) {
    	int ans=1;
    	while(b) { if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1; }
    	return ans;
    }
    int get_one(int x)
    {
    	int js=0;
    	while(x)
    	{
    		if(x&1) js++;
    		x>>=1;
    	}
    	return js;
    }
    
    int main()
    {
    	T=read();
    	while(T--) {
    		n=read(),m=read(),h=read(),w=read(),Ans=0,x=0,y=0;
    		for(int i=1;i<=n;i++)
    			sz[i].x_1=read(),sz[i].y_1=read(),sz[i].x_2=read(),sz[i].y_2=read(),sz[i].v=read(),
    			qx[++x]=sz[i].x_1,qx[++x]=sz[i].x_2,qy[++y]=sz[i].y_1,qy[++y]=sz[i].y_2;
    		qx[++x]=1,qx[++x]=h+1,qy[++y]=1,qy[++y]=w+1;
    //		init();
    		sort(qx+1,qx+1+x);
    		x=unique(qx+1,qx+1+x)-qx-1;
    		sort(qy+1,qy+1+y);
    		y=unique(qy+1,qy+1+y)-qy-1;
    		for(int i=0;i<(1<<n);i++)
    		{
    			for(int j=1;j<x;j++) 
    				for(int k=1;k<y;k++) 
    					f[j][k]=m;
    			for(int j=0;j<=n;j++)
    				for(int k=lower_bound(qx+1,qx+1+x,sz[j].x_1)-qx;qx[k]!=sz[j].x_2;k++)
    					for(int l=lower_bound(qy+1,qy+1+y,sz[j].y_1)-qy;qy[l]!=sz[j].y_2;l++)
    						f[k][l]=min(f[k][l],sz[j].v-(i>>(j-1)&1));
    			int res=1;
    			for(int j=1;j<x;j++)
    				for(int k=1;k<y;k++)
    					res=res*qpow(f[j][k],(qx[j+1]-qx[j])*(qy[j+1]-qy[j]));
    			Ans=((Ans+get_one(i)&1?-1:1+mod)*res%mod)%mod;
    		}
    		printf("%d\n",Ans);
    	}
    	return 0;
    }
    		
    			
    
  • 相关阅读:
    结构~函数~输入输出
    常用缀名
    结构
    枚举
    int argc char*argv[]
    字符串的操作
    字符串函数#include<string.h>
    指针的应用
    2019.1.25~2019.1.30学习总结
    v-for
  • 原文地址:https://www.cnblogs.com/jcgf/p/15238828.html
Copyright © 2011-2022 走看看