哎,太颓废了,差不多两个月没怎么写博客了
今天来补了一下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 <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
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.代码的话
是参照大牛写的,就没有贴出来的必要啦
总的来说,想和做这些题还是感觉挺舒服的,继续努力吧,奋斗的自己才最有生命力
Codeforces343 div2 题解
最新推荐文章于 2025-04-27 15:38:06 发布