博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

8.20 附加赛3


2018.8.20 附加赛3

比赛链接

A 斯(贪心)

题目链接

某状态下的最差情况收益就是min(wa,wb)-cost。当然是从大的取,同时尽量保证wa,wb均衡。
枚举一下,Ans时刻取个max就行了。
复杂度在于排序 O(nlogn)。Ai只有四位小数且<=10,可以用桶排降到O(n)。

//138ms	2392kb
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e5+5;

int n;
double A[N],B[N];
char IN[MAXIN],*SS=IN,*TT=IN;

inline double read()
{
	double x=0,y=0.1; register char c=gc();
	for(; !isdigit(c)&&c!='.'; c=gc());
	for(; isdigit(c); x=x*10+c-'0',c=gc());
	for(c=='.'&&(c=gc()); isdigit(c); x+=(c-'0')*y,y*=0.1,c=gc());
	return x;
}

int main()
{
	n=read();
	for(int i=1; i<=n; ++i) A[i]=read();
	for(int i=1; i<=n; ++i) B[i]=read();
	std::sort(A+1,A+1+n), std::sort(B+1,B+1+n);
	double Ans=0,nowa=0,nowb=0;
	for(int a=n,b=n,cost=0; a||b; ++cost,Ans=std::max(Ans,std::min(nowa,nowb)-cost))
	{
		if(!b||(nowa<=nowb && a)) nowa+=A[a--];
		else nowb+=B[b--];
	}
	printf("%.4lf\n",Ans);

	return 0;
}

B 给(DP)

题目链接

DP,f[i][j]表示当前有i个叶子,树中根到所有叶子的路径中向左的边都不超过j条,的方案数。
根节点的两棵左右子树算是两个独立的子问题,即枚举左子树的叶节点数k后,可以直接f[k]*f[i-k]拼起来。
再具体就是左子树中所有向左边不超过j-1条的叶节点都可以接上i,然后乘上右子树所有路径向左边不超过j条的方案数。
\(f[i][j]=\sum_{k=1}^{j-1}f[k][j-1]*f[i-k][j]\)
至于为什么只枚举左儿子而不用*2。。不知道。。求dalao解答。。(枚举是对称的?)
这样是O(n^3),得分35~40。
注意到转移是个卷积形式,用NTT转移 写的好的话能拿到60。

满分做法:还是要换种状态表示,考虑枚举一个一个放叶子:f[i][j]表示已有i个叶子,当前放的叶子到根节点的路径有j条向左边。
下一个点要么放在当前叶子的左儿子。这样不会改变叶子数,j要加1,即转移到f[i][j+1]。
要么放在最近有左儿子但是没放右儿子的点,作为其右儿子。这样能转移到叶子数+1,j-1的状态,即f[i+1][j-1]。
f[i][0]就表示已有i个叶子,且所有有左儿子的点都有右儿子了,即k=i时的答案。
因为是枚举了所有状态下的唯二两种转移。。嗯。。所以说(这么说)没问题吧。。
复杂度O(n^2)。

唉 感觉两个DP都好迷啊。。

//376ms	95800kb(莫名慢好多 明明都差不多)
#include <cstdio>
#define mod (998244353)
#define rg register
//#define Add(x,v) x+=v,x>=mod&&(x-=mod)
const int N=5005;

int f[N][N];
inline void Add(int &x,int v){
	x+=v, x>=mod&&(x-=mod);
}

int main()
{
	int m,n; scanf("%d%d",&m,&n);
	f[1][0]=1;
	for(rg int i=1; i<n; ++i)
	{
		Add(f[i][1],f[i][0]);
		for(rg int j=1; j<m; ++j)
			Add(f[i][j+1],f[i][j]), Add(f[i+1][j-1],f[i][j]);
	}
	for(rg int i=1; i<=n; ++i) printf("%d\n",f[i][0]);

	return 0;
}

C 普

题目链接


posted @ 2018-08-23 16:45  SovietPower  阅读(122)  评论(0编辑  收藏  举报