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 Round #197 (Div. 2)
- Codeforces Round #198 (Div. 1)
- Codeforces 405E Codeforces Round #238 (Div. 2)E
- Codeforces 407C Codeforces Round #239 (Div. 1)C
- CodeForces 449A - Jzzhu and Chocolate
- CodeForces 449 B. Jzzhu and Cities
- Codeforces Round #265 (Div. 2)
- Codeforces #310 div2 C. Case of Matryoshkas
- 状态压缩DP codeforces 244 Problem C. The Brand New Function 和 codeforces 165 E. Compatible Numbers
- codeforces 16 Problem E fish
- Codeforces Round332 部分题解
- CodeForces 603A_Alternative Thinking (DP)
- CodeForces 602B_Approximating a Constant Range_DP
- Codeforces round #247 for Div. 2
- Codeforces Round #246 (Div. 2)
- Codeforces #264(div 2)D.Gargari and Permutations
- Codeforces Round #236 (Div. 2)------A,B
- codeforces 257 div2 B
- Codeforces Gym100571A Cursed Query
- Codeforces Gym100342E Minima