您的位置:首页 > 其它

Codeforces Round #343 (Div. 2)

2016-02-22 16:28 381 查看

C. Famil Door and Brackets

dp。状态dp(i,j,k),i表示填充到了第几个括号,j表示当前左括号比右括号多多少,k表示当前在那个子串的左边还是右边填充,状态转移见代码。要注意一些情况,比如要保证任何时候前缀的左括号不少于右括号,后缀的右括号不少于左括号。还有当n=m时,判断子串的合法性。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int mod = 1e9+7;

char str[100010];

ll dp[2010][2010][2];

int main(){
int n,m;
while(cin>>n>>m){
memset(dp,0,sizeof(dp));
scanf("%s",str);
int lcnt=0;
int rcnt=0;
int cnt=0;
int MAX=-1e9;
int MAX2=-1e9;

for(int i=m-1;i>=0;i--){
if(str[i]=='('){
cnt++;
}else{
cnt--;
}
MAX2=max(MAX2,cnt);
}

cnt=0;
bool valid = 1;
for(int i=0;i<m;i++){
if(str[i]=='('){
lcnt++;
cnt--;
}else{
rcnt++;
cnt++;
}
if(rcnt>lcnt)valid=0;
MAX=max(MAX,cnt);
}

int d=n-m;
if(lcnt+d<rcnt){
}else if(rcnt+d<lcnt){
}else{
dp[0][0][0]=1;
for(int i=1;i<=d;i++){
for(int j=0;j<=d;j++){
if(d-i>=MAX2 && j<d){
dp[i][j+1][0] += dp[i-1][j][0];
dp[i][j+1][0] %= mod;
}
if(d-i>=MAX2 && j>0){
dp[i][j-1][0] += dp[i-1][j][0];
dp[i][j-1][0] %= mod;
}

if(j>=MAX && j+lcnt-rcnt+1<=d && j+lcnt-rcnt+1>=0){
dp[i][j+lcnt-rcnt+1][1] += dp[i-1][j][0];
dp[i][j+lcnt-rcnt+1][1] %= mod;
}
if(j>=MAX && j+lcnt-rcnt-1<=d && j+lcnt-rcnt-1>=0){
dp[i][j+lcnt-rcnt-1][1] += dp[i-1][j][0];
dp[i][j+lcnt-rcnt-1][1] %= mod;
}

if(j<d){
dp[i][j+1][1] += dp[i-1][j][1];
dp[i][j+1][1] %= mod;
}
if(j>0){
dp[i][j-1][1] += dp[i-1][j][1];
dp[i][j-1][1] %= mod;
}
}
}
}

ll ans = dp[d][0][1];
if(rcnt-lcnt>=0 && rcnt-lcnt<=d){
ans += dp[d][rcnt-lcnt][0];
}
ans %= mod;
if(n==m && !valid)ans=0;
cout<<ans<<endl;
}
return 0;
}


D. Babaei and Birthday Cake

由于任意蛋糕的上方只能是编号更大的蛋糕,所以逆序处理。将蛋糕体积离散化,每次计算用新的蛋糕作为“底座”时最大总体积,方法是线段树区间更新单点查询,线段树的节点维护对应体积为“底座”时的最大总体积,每次拿合法的最大的总体积叠在上面。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int mod = 1e9+7;
const int maxn = 100010;
const double PI = 3.14159265358979323846264;

ll r[maxn];
ll h[maxn];

ll v[maxn];

struct node{
int l,r;
ll val;
}tree[maxn<<2];

void build_tree(int rt,int l,int r){
tree[rt].l=l;
tree[rt].r=r;
tree[rt].val = 0;
if(l==r)return;
int mid = (l+r)>>1;
build_tree(rt<<1,l,mid);
build_tree((rt<<1)|1,mid+1,r);
}

void update(int rt,int l,int r,ll val){
if(tree[rt].l == l && tree[rt].r == r){
tree[rt].val = max(val,tree[rt].val);
return;
}
int mid = (tree[rt].l + tree[rt].r)>>1;
if(r<=mid){
update(rt<<1,l,r,val);
}else{
if(l>mid){
update((rt<<1)|1,l,r,val);
}else{
update(rt<<1,l,mid,val);
update((rt<<1)|1,mid+1,r,val);
}
}
}

ll query(int rt,int x){
if(tree[rt].l == tree[rt].r){
return tree[rt].val;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(x<=mid){
return max(tree[rt].val,query(rt<<1,x));
}else{
return max(tree[rt].val,query((rt<<1)|1,x));
}
}

map<ll,int> mp;

int main(){
int n;
cin>>n;
for(int i = 1;i<=n;i++){
scanf("%I64d %I64d",&r[i],&h[i]);
v[i] = r[i]*r[i]*h[i];
mp[v[i]] = 0;
}

int k=1;
for(auto it=mp.begin();it!=mp.end();it++){
it->second = k++;
}

build_tree(1,1,k);

double ans = 0;
for(int i=n;i>0;i--){
int id = mp[v[i]];
double tmp = query(1,id+1);
tmp+=v[i];
update(1,1,id,tmp);
ans=max(ans,tmp);
}
printf("%.12f\n",ans*PI);
return 0;
}


E. Famil Door and Roads

解题核心是求LCA。先分析下要使u-v成环需要满足什么条件:u-v在树上有且仅有一条简单路径,新的边只要加在u-v两个端点的两头,就能成环。所以我们只要计算两头所有点到u/v的平均距离即可。分两种情况,若lca不是u或v,两端的点就是u和v的子树;否则,假设v是u和v的lca,u那头的点还是u的子树,v那头的点则是整棵树砍掉v往u方向的孩子。在dfs时,去计算每个点到其子孙的总距离和到所有点的总距离,就可以进而算出上述平均距离。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int maxn = 100010;

int head[maxn];
int pre[maxn<<1];
int Next[maxn<<1];
int tot;
int p[maxn][20];
int dep[maxn];
int size[maxn];

double dist_down[maxn];
double dist_all[maxn];

void init(){
memset(head,-1,sizeof(head));
dep[1]=1;
tot=0;
}

void dfs(int u,int fa){
//
int tmp = fa;
for(int i=0;i<=16;i++){
p[u][i] = tmp;
tmp = p[tmp][i];
}
//
size[u]=1;
for(int i=head[u];~i;i=pre[i]){
int v=Next[i];
if(v==fa)continue;
dep[v]=dep[u]+1;
dfs(v,u);
size[u]+=size[v];
dist_down[u] += (dist_down[v]+size[v]);
}
}

void dfs2(int u,int fa){
if(u==1){
dist_all[u] = dist_down[u];
}else{
dist_all[u] = dist_all[fa] - size[u] + (size[1]-size[u]);
}

for(int i=head[u];~i;i=pre[i]){
int v=Next[i];
if(v==fa)continue;
dfs2(v,u);
}
}

int get_ancestor(int u,int x){
int k = 0;
while(x){
if(x&1){
u=p[u][k];
}
k++;
x>>=1;
}
return u;
}

int lca(int u,int v){
if(dep[v]>dep[u]){
swap(u,v);
}

u=get_ancestor(u,dep[u]-dep[v]);
if(u==v)return u;
int k=16;
while(k>=0){
if(p[u][k]!=p[v][k]){
u = p[u][k];
v = p[v][k];
}
k--;
}
return p[u][0];
}

void addEdge(int u,int v){
Next[tot]=v;
pre[tot]=head[u];
head[u]=tot++;
//
Next[tot]=u;
pre[tot]=head[v];
head[v]=tot++;
}

int main(){
init();

int n,m;
cin>>n>>m;

int test =0;
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
if(i==1)test=u;
addEdge(u,v);
}

dfs(1,0);
dfs2(1,0);

for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
if(dep[u]<dep[v]){
swap(u,v);
}
int LCA = lca(u,v);
double ans = 0;

if(LCA==v){
int son = get_ancestor(u,dep[u]-dep[v]-1);
ans = dist_down[u]/size[u] + (dist_all[v]-dist_down[son]-size[son])/(size[1]-size[son]);
ans += (dep[u]-dep[v]+1);
}else{
ans = dist_down[u]/size[u] + dist_down[v]/size[v];
ans += (dep[u]+dep[v]-dep[LCA]*2+1);
}
printf("%.10f\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces