Codeforces343 div2 题解

哎,太颓废了,差不多两个月没怎么写博客了

今天来补了一下codeforces343 的 div2,说一说自己的感受吧
前面两题就直接略过了.从C题开始

C题是给长度为m的串,凑成长度为n的合法的串.注意到n-m <= 2000,
相信大家都明白,这类题从dp角度就是经典的dp[i][j]长度为i,某两者
之间的差值的方案数.这类的dp.转移起来也挺简单.考虑第i位是(或者)
的情况.
(,那么dp[i][j] += dp[i-1][j-1] (当然前提j肯定>0罗)
),那么dp[i][j] += dp[i-1][j+1] (没有限制对吧?)
由于有p+s+q,要满足题目中的前缀和大于0.突破口肯定在s.s中的最小的
前缀和设为lx.整个s的前缀设为sum.p+s的前缀必须是>=0,p+s+q的前缀也
必须大于等于0.从而我们得到枚举p和q的长度以及(和)的差值.从而得到
答案.进一步,发现p+q是定值设一个为x.另一个则为n-m-x.再枚举(与)的
差值t,此时只要t+lx>=0并且t+sum <= n - m - k即q的长度.此时t+sum
表示的是右边)比(多的情况.而(和)两者差值又可以相互对应即(比)多k的
方案数和)比(多的方案数是一致的.再将p和q的部分相乘,累加即可得到答案

代码的话,实现起来还是很简单的,这里就不显拙啦


D题其实就是一个LIS.这类题目都有个通用的N*N的dp式子
dp[i] = max(dp[j]) (a[j] < a[i])
这之类的.将需要的条件的那个变量进行离散化.对于每个量a[i]通过二分查找
找到对应于线段树中的位置p.查询1~(p-1)位置的最大或者最小值.累加a[i]至
其上.再将这个答案插入到线段树的p处.每次取最大或者最小,就是最后的答案

代码还是贴一下

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int MAX_N = 100000 + 50;
const int MOD = 1e9 + 7;
const double PI = acos(-1);

struct Cake{
	int r;
	int h;
	int id;
	Cake(){

	}
	Cake(int r,int h,int id):r(r),h(h),id(id){

	}
}p[MAX_N];

struct Seg{
#define lson(x) (x << 1)
#define rson(x) (x << 1 | 1)
	ll maxv[MAX_N << 2];
	int q;
	ll val;
	int ql,qr;

	void setp(int x,ll v){
		q = x;
		val = v;
	}

	void sets(int l,int r,ll v){
		ql = l;
		qr = r;
		val = v;
	}

	void push_up(int rt){
		maxv[rt] = max(maxv[lson(rt)],maxv[rson(rt)]);
	}

	void clear(){
		memset(maxv,0,sizeof(maxv));
	}

	void update(int rt,int L,int R){
		if (L == R){
			maxv[rt] = val;
			return ;
		}

		int MID = (L + R) >> 1;

		if (q <= MID)	update(lson(rt),L,MID);
		else update(rson(rt),MID+1,R);
		push_up(rt);
	}

	ll query(int rt,int L,int R){
		if (ql <= L && R <= qr){
			return maxv[rt];
		}
		ll ans = 0;
		int MID = (L + R) >> 1;
		if (ql <= MID)	ans = max(ans,query(lson(rt),L,MID));
		if (MID < qr)	ans = max(ans,query(rson(rt),MID+1,R));
		return ans;
	}

}it;
int n;

bool cmp(Cake a,Cake b){
	return (ll)a.r * a.r * a.h < (ll)b.r * b.r * b.h;
}

ll X[MAX_N];
int main(){
	//freopen("te.txt","r",stdin);
	scanf("%d",&n);
	int r,h;
	for (int i = 1;i <= n;i ++){
		scanf("%d%d",&r,&h);
		p[i] = Cake(r,h,i);
		X[i] = (ll)p[i].r * p[i].r * p[i].h;
	}

	sort(X+1,X+n+1);
	ll res = 0;
	int cnt = unique(X+1,X+n+1) - X - 1;
	it.clear();
	ll ans;
	for (int i = 1;i <= n;i ++){
		ll tmp = (ll)p[i].r * p[i].r * p[i].h;
		int pos = lower_bound(X+1,X+cnt+1,tmp) - X;
		if (pos == 1)
            ans = tmp;
        else {
            it.sets(1,pos-1,0);
            ans = it.query(1,1,cnt);
            ans += tmp;
        }
		res = max(res,ans);
		it.setp(pos,ans);
		it.update(1,1,cnt);
	}
	printf("%.9lf\n",PI * res);
	return 0;
}


E题,题目都没看懂,然后跟着大牛看了看题解,看着感觉挺厉害的.总的
就是LCA + DP.看懂了是看懂了,但是怎么想出来的还是不会.总的是
维护一个dep深度值,一个sall[i]所有节点到i的距离和,sdown[i]i为根的
子树所有节点到i的距离和.sz[i]i为根的子树的节点个数.讨论LCA(u和v)
是否与其中之一重合.
若是,则设v为祖先,那么一定是选v以及v以上的部分中的一个点和u的子树
中的点.sdown[u] / sz[u] + (sall[v] - sdown[v1] - sz[v1]) / (n - sz[v1])
v1是u,v路径上的v的子节点即v的儿子
若不是,则是u的子树和v的子树中各选一个点
sdown[u] / sz[u] + sdown[v] / sz[v].
这之后各自的答案还要累加一个u到v的距离+1.
u和v的距离为dep[u] + dep[v] - 2 * dep[lca(u,v)];成环还需+1.代码的话
是参照大牛写的,就没有贴出来的必要啦


总的来说,想和做这些题还是感觉挺舒服的,继续努力吧,奋斗的自己才最有生命力

你可能感兴趣的:(Codeforces,Data,structure,Codeforces343,div2,题)