昼夜切换动画

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;
}
		
			
posted @ 2021-09-07 16:23  smyslenny  阅读(226)  评论(0编辑  收藏  举报