test 11-10 [水题 状压DP dfs序+线段树]
2016-11-10 16:55
387 查看
第一题水题,略过。。。
状压dp,用记忆化搜索比较简便,主要是再加一个状态,表示上一次取的,即可得转移方程:
dp(S,i,j)=max{dp(S’,k,j-1)}
其中,j,这个状态是指取了多少个,但是S已经表示了,记忆化的时候不用加这一维,这里只是为了方便。
经过推导,可得:ans[u]=(k−d[u])∗numson[u]+Sigma(d[son[u]])
然后把点用dfs序存下
最后线段树,区间修改,区间查找
即:最终的值等于k减去该点深度,乘以子树大小加上子树深度和。
记住要记录add和tim(加的次数)的值,而且add可能为0,因此判断pushdown的标准是tim不为0而不是add
T2
【题目描述】
我们要从n种食物选m个出来,安排一个顺序吃掉它(们),每种食物有个美味值ai,然后我们有k个规则,每个规则有 xi, yi 和 ci三个数,如果吃完第xi种食物接下来马上吃第yi种食物,第j种食物的美味值会增加ci。每种食物至多吃一个,求美味值最大的和是多少?
【输入格式】
第一行有三个数n,m,k,k代表有k个规则(0<=k<=n*(n-1))。 第二行有n个数字代表每个食物的美味值。 接下去有k行,每行三个数xi,yi,ci。保证没有任意两个规则的xi和yi同时相同。
【输出格式】
一行一个数代表答案
【sample input1】
2 2 1 1 1 2 1 1
【sample output1】
3
【sample input 2】
4 3 2 1 2 3 4 2 1 5 3 4 2
【sample output 2】
12
【数据范围】
30% m<=n<=5 ,0<=ci,ai<=1e5 100% m<=n<=18,0<=ci,ai<=1e9
状压dp,用记忆化搜索比较简便,主要是再加一个状态,表示上一次取的,即可得转移方程:
dp(S,i,j)=max{dp(S’,k,j-1)}
其中,j,这个状态是指取了多少个,但是S已经表示了,记忆化的时候不用加这一维,这里只是为了方便。
代码样本:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 25 #define maxbit 300000 typedef long long ll; ll f[maxbit][maxn],w[maxn],ad[maxn][maxn]; int p[maxn],n,m,k; bool vis[maxbit][maxn]; ll dp(int s,int las,int nu) { if(nu==m)return 0; if(vis[s][las])return f[s][las]; ll &ans=f[s][las]; for(int i=1;i<=n;i++) { if(s&p[i])continue; if(ad[las][i]) ans=(ll)max(ans,dp(s|p[i],i,nu+1)+ad[las][i]+w[i]); else ans=(ll)max(ans,dp(s|p[i],i,nu+1)+w[i]); } vis[s][las]=true; return ans; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) { scanf("%I64d",&w[i]); p[i]=1<<(i-1); } int a,b; ll val; while(k--) { scanf("%d%d%I64d",&a,&b,&val); ad[a][b]=val; } printf("%I64d",dp(0,0,0)); return 0; }
T3
【题目描述】
历史上有一个著名的王国。它的所有城市互相连通并且构成一棵树。城市1为首都也就是这棵树的根。 因为外来的入侵,国王决定在某些城市加派士兵。所有城市初始士兵数量为0。当城市i 被加派了k 名士兵时。城市i 的所有子城市需要被加派k+1 名士兵。这些子城市的所有子城市需要被加派k+2 名士兵。以此类推。 当然,加派士兵的同时,国王也需要不断了解当前的情况。于是他随时可能询问以城市i 为根的子树中的所有城市共被加派了多少士兵。 你现在是国王的军事大臣,你能回答出国王的每个询问么?
【输入】
第一行,包含两个整数N,P 代表城市数量以及国王的命令的数量。 接下来的P 行,每行代表国王的一个命令,命令分两种 A X K :在城市X 加入K 个士兵 Q X :询问以城市X 为根的子树中所有士兵数量的和
【输出】
对于每个Q,输出答案。
【输入样例】
7 10 1 1 2 2 5 5 Q 1 A 2 1 Q 1 Q 2 Q 5 A 5 0 Q 5 A 3 1 Q 1 Q 2
【输出样例】
0
11
11
8
10
14
13
【数据范围】
对于50%的数据, 1<=N<=1000 1<=P<=300 对于100%的数据, 1<=N<=50000 1<=P<=100000 1<=X<=N 0<=K<=1000
经过推导,可得:ans[u]=(k−d[u])∗numson[u]+Sigma(d[son[u]])
然后把点用dfs序存下
最后线段树,区间修改,区间查找
即:最终的值等于k减去该点深度,乘以子树大小加上子树深度和。
记住要记录add和tim(加的次数)的值,而且add可能为0,因此判断pushdown的标准是tim不为0而不是add
代码样本:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<algorithm> using namespace std; #define L(u) (u<<1) #define R(u) ((u<<1)|1) #define maxn 50005 struct tre{ int l,r; }nod[maxn*4]; typedef long long ll; ll d[maxn],ma[maxn],sum[maxn*4],ad[maxn*4],sd[maxn],ti[maxn*4],k; int head[maxn],tov[maxn],next[maxn],n,p,a,size[maxn],dfn[maxn],num; int dfs(int u) { size[u]=1; dfn[u]=++num; ma[num]=u; int v=head[u]; while(v) { d[tov[v]]=d[u]+1; size[u]+=dfs(tov[v]); v=next[v]; } return size[u]; } void build(int u,int le,int ri) { nod[u].l=le,nod[u].r=ri; if(le==ri) { return ; } int mid=(le+ri)/2; build(L(u),le,mid); build(R(u),mid+1,ri); } ll upg(ll val,int po) { return val-d[po]; } void pushdown(int u) { sum[L(u)]+=(nod[L(u)].r-nod[L(u)].l+1)*ad[u]+(sd[nod[L(u)].r]-sd[nod[L(u)].l-1])*ti[u]; sum[R(u)]+=(nod[R(u)].r-nod[R(u)].l+1)*ad[u]+(sd[nod[R(u)].r]-sd[nod[R(u)].l-1])*ti[u]; ad[L(u)]+=ad[u]; ad[R(u)]+=ad[u]; ti[L(u)]+=ti[u]; ti[R(u)]+=ti[u]; ad[u]=0; ti[u]=0; } void update(int u,int le,int ri,ll val,int po) { if(nod[u].l>=le&&nod[u].r<=ri) { sum[u]+=(nod[u].r-nod[u].l+1)*upg(val,po)+sd[nod[u].r]-sd[nod[u].l-1]; ad[u]+=upg(val,po); ti[u]++; return; } if(ad[u]||ti[u]) pushdown(u); int mid=(nod[u].l+nod[u].r)/2; if(ri<=mid)update(L(u),le,ri,val,po); else if(le>mid)update(R(u),le,ri,val,po); else { update(L(u),le,mid,val,po); update(R(u),mid+1,ri,val,po); } sum[u]=sum[L(u)]+sum[R(u)]; } ll query(int u,int le,int ri) { if(nod[u].l==le&&nod[u].r==ri) { return sum[u]; } if(ad[u]||ti[u])pushdown(u); int mid=(nod[u].l+nod[u].r)/2; if(ri<=mid)return query(L(u),le,ri); else if(le>mid) return query(R(u),le,ri); else return query(L(u),le,mid)+query(R(u),mid+1,ri); } int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d%d",&n,&p); for(int i=2;i<=n;i++) { scanf("%d",&a); tov[i]=i; next[i]=head[a]; head[a]=i; } d[1]=1; dfs(1); for(int i=1;i<=n;i++) sd[i]=sd[i-1]+d[ma[i]]; build(1,1,n); char op; while(p--) { scanf(" %c ",&op); if(op=='A') { scanf("%d%I64d",&a,&k); update(1,dfn[a],dfn[a]+size[a]-1,k,a); } else { scanf("%d",&a); printf("%I64d\n",query(1,dfn[a],dfn[a]+size[a]-1)); } } return 0; }
相关文章推荐
- thinking in java test5.5练习(10)(11)(12)finalize()方法
- thinking in java test5.5练习(10)(11)(12)finalize()方法
- 专题(弱点)Dp训练总结【状压Dp*1+区间Dp*5+数位dp*3+树型Dp*2】【10/11】
- 解决oracle 10/11 g Express Edition不能JDBC连接的问题
- 10 05 11 306
- 1779 Problem A 算法10-10,10-11:堆排序
- C#从入门到入土——_17_11_10
- QTP_在win7旗舰版上安装qtp10/11提示windows installer安装日志错误
- 10-11-12
- test11
- 11-10-26 存疑 --- 已解决
- IE10/11 滚动条自动隐藏~
- linux系统编程之信号 test10_9.c
- U盘 安装 CentOS 5.4 / Fefora 10/11/12
- 10,11,12月学习计划
- Response 对象 server对象 10/11
- 10 11 04 悲剧人生
- 10 11 20 赶
- 背水一战 Windows 10 (11) - 资源: CustomResource, ResourceDictionary, 加载外部的 ResourceDictionary 文件
- Educational Codeforces Round 11 B. Seating On Bus 水题