HAOI2015 泛做
T1
有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的受益。问受益最大值是多少。N,K<=2000
这个树形dp不是很好想...因为贡献十分混乱...
题解十分神奇...我们记f[i][j]为i的子树有j个黑点的最大权值。
注意直接dp十分蛋疼,这个权值指的是,这个子树内部的贡献,以及i与父亲之间的边对答案的贡献(比如这条边对黑点对距离和的贡献就是子树内部的黑点数*子树外部的黑点数*这条边的权值)。
这个转移就是正常的子树合并...似乎子树合并的题目这个trick十分有用啊...
- #include <iostream>
- #include <stdio.h>
- #include <math.h>
- #include <string.h>
- #include <time.h>
- #include <stdlib.h>
- #include <string>
- #include <bitset>
- #include <vector>
- #include <set>
- #include <map>
- #include <queue>
- #include <algorithm>
- #include <sstream>
- #include <stack>
- #include <iomanip>
- using namespace std;
- #define pb push_back
- #define mp make_pair
- typedef pair<int,int> pii;
- typedef long long ll;
- typedef double ld;
- typedef vector<int> vi;
- #define fi first
- #define se second
- #define fe first
- #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
- #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
- #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
- #define es(x,e) (int e=fst[x];e;e=nxt[e])
- #define cif(x) if(x) continue
- #define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");}
- #define TIMER cerr<<clock()<<"ms\n"
- #define gmax(a,b) if((a)<(b)) (a)=(b);
- #define gmin(a,b) if((a)>(b)) (a)=(b);
- #define SZ 666666
- Edgc
- int n,k,sz[SZ];
- ll dp[2333][2333],tmp[2333];
- void dfs(int x,int f=0,int fv=0)
- {
- int cs=1;
- for es(x,e)
- {
- int b=vb[e]; cif(b==f);
- dfs(b,x,vc[e]);
- int cc=cs+sz[b];
- for(int i=0;i<=min(cc,k);i++) tmp[i]=0;
- for(int i=0;i<=cs&&i<=k;i++)
- {
- for(int j=0;j<=sz[b]&&j<=k;j++)
- {
- if(i+j>k) continue;
- gmax(tmp[i+j],dp[x][i]+dp[b][j]);
- }
- }
- for(int i=0;i<=min(cc,k);i++) dp[x][i]=tmp[i];
- cs=cc;
- }
- sz[x]=cs;
- for(int i=0;i<=cs&&i<=k;i++)
- {
- if(cs+(k-i)>n)
- {
- dp[x][i]=-2147400000; continue;
- }
- //xblack=i xwhite=cs-i
- //wblack=k-i wwhite=n-cs-(k-i)
- dp[x][i]+=(ll)i*(k-i)*fv;
- dp[x][i]+=(ll)(cs-i)*(n-cs-(k-i))*fv;
- }
- }
- int main()
- {
- scanf("%d%d",&n,&k);
- for(int i=1;i<n;i++)
- {
- int a,b,c;
- scanf("%d%d%d",&a,&b,&c);
- adde(a,b,c);
- }
- dfs(1);
- cout<<dp[1][k]<<"\n";
- }
T2
链剖裸题就不说了...
似乎有两遍dfs序的做法写了写没调出来...
- #include <iostream>
- #include <stdio.h>
- #include <stdlib.h>
- using namespace std;
- #define SZ 666666
- typedef long long ll;
- ll a1[210001],a2[210001];
- ll qzh(int r)
- {
- ll s1=0,s2=0;
- for(int i=r;i>=1;i-=i&-i) s1+=a1[i], s2+=a2[i];
- return (r+1)*s1-s2;
- }
- ll sum(int l,int r)
- {
- return qzh(r)-qzh(l-1);
- }
- void edt(ll a,ll s1)
- {
- ll s2=a*s1;
- for(;a<=210000;a+=a&-a) a1[a]+=s1, a2[a]+=s2;
- }
- void edt(int l,int r,ll a) {edt(l,a); edt(r+1,-a);}
- namespace lct
- {
- #define SZ 666666
- int n,S=0,ns[SZ],fs[SZ],ss[SZ],fa[SZ],siz[SZ],ws[SZ],dep[SZ],fe[SZ],top[SZ],X=0,ls[SZ];
- void ad_de(int x,int y)
- {
- ++S; ns[S]=fs[x]; fs[x]=S; ss[S]=y;
- }
- void adde(int x,int y) {ad_de(x,y); ad_de(y,x);}
- void dfs1(int cur)
- {
- siz[cur]=1; ws[cur]=0;
- int csc=-233;
- for(int x=fs[cur];x;x=ns[x])
- {
- int c=ss[x];
- if(c==fa[cur]) continue;
- fa[c]=cur;
- dep[c]=dep[cur]+1;
- dfs1(c);
- if(siz[c]>csc) csc=siz[c], ws[cur]=c;
- siz[cur]+=siz[c];
- }
- }
- void dfs2(int cur,int tp)
- {
- fe[cur]=++X; top[cur]=tp;
- if(ws[cur]) dfs2(ws[cur],tp);
- for(int x=fs[cur];x;x=ns[x])
- {
- int c=ss[x];
- if(c!=ws[cur]&&c!=fa[cur]) dfs2(c,c);
- }
- ls[cur]=X;
- }
- void s1(int cur,int V)
- {
- edt(fe[cur],ls[cur],V);
- }
- ll s2(int x)
- {
- int u=1,v=x; ll ans=0;
- int f1=top[u],f2=top[v];
- while(f1!=f2)
- {
- if(dep[f1]<dep[f2]) swap(f1,f2), swap(u,v);
- ans+=sum(fe[f1],fe[u]);
- u=fa[f1]; f1=top[u];
- }
- if(dep[u]>dep[v]) swap(u,v);
- ans+=sum(fe[u],fe[v]);
- return ans;
- }
- }
- int qq[233333];
- int main()
- {
- int n,m;
- scanf("%d%d",&n,&m);
- for(int i=1;i<=n;i++)
- {
- scanf("%d",qq+i);
- }
- for(int i=1;i<n;i++)
- {
- int a,b;
- scanf("%d%d",&a,&b);
- lct::adde(a,b);
- }
- lct::dfs1(1); lct::dfs2(1,1);
- for(int i=1;i<=n;i++) edt(lct::fe[i],lct::fe[i],qq[i]);
- for(int i=1;i<=m;i++)
- {
- int p; scanf("%d",&p);
- if(p==1)
- {
- int x,a; scanf("%d%d",&x,&a);
- edt(lct::fe[x],lct::fe[x],a);
- }
- else if(p==2)
- {
- int x,a; scanf("%d%d",&x,&a);
- lct::s1(x,a);
- }
- else
- {
- int x; scanf("%d",&x);
- printf("%lld\n",lct::s2(x));
- }
- }
- }
T3
这个sg题真是感人至深啊...
参考链接 http://blog.csdn.net/lych_cys/article/details/50896005
首先我们可以发现问题可以转化为存在若干白点,然后将所有点翻转成黑点,先全部翻转的为胜。因为如果从黑点开始翻转后手可以翻过来...
那么我们就可以假装只有一个白点,然后把sg值异或在一起。
算一下sg,可以发现一个白点i可以转移到2i,2i、3i,2i、3i、4i...
那就是说sg[i]=mex{sg[i]^sg[2i],sg[i]^sg[2i]^sg[3i]...}
经过仔细观察(归纳证明)可以发现sg[i]只与n/i有关。
那么我们就可以暴力像莫比乌斯反演那样做,预处理时大模拟显然是不超过O(n)的,对于<=根号n的我们直接存,>根号n的就用n除一下再存。
- #include <iostream>
- #include <stdio.h>
- #include <math.h>
- #include <string.h>
- #include <time.h>
- #include <stdlib.h>
- #include <string>
- #include <bitset>
- #include <vector>
- #include <set>
- #include <map>
- #include <queue>
- #include <algorithm>
- #include <sstream>
- #include <stack>
- #include <iomanip>
- using namespace std;
- #define pb push_back
- #define mp make_pair
- typedef pair<int,int> pii;
- typedef long long ll;
- typedef double ld;
- typedef vector<int> vi;
- #define fi first
- #define se second
- #define fe first
- #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
- #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
- #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
- #define es(x,e) (int e=fst[x];e;e=nxt[e])
- #define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");}
- #ifdef LOCAL
- #define TIMER cerr<<clock()<<"ms\n"
- #else
- #define TIMER
- #endif
- #define SZ 666666
- int nxt(int x,int n)
- {
- if(x==n) return n+1;
- return n/(n/(x+1)); //end
- }
- int n,k,sg[SZ],fsg[SZ],Q,tmp[SZ];
- int main()
- {
- scanf("%d%d",&n,&k); Q=sqrt(n)+1;
- for(int i=1;i<=n;i=nxt(i,n))
- {
- int cur=0; tmp[cur]=i;
- for(int j=2;j<=i;j=nxt(j,i))
- {
- int t=i/j,p=(t<=Q)?sg[t]:fsg[n/t];
- tmp[cur^p]=i;
- if((i/t-i/(t+1))&1) cur^=p;
- }
- cur=0;
- while(tmp[cur]==i) ++cur;
- if(i<=Q) sg[i]=cur;
- else fsg[n/i]=cur;
- }
- while(k--)
- {
- int ans=0,m;
- scanf("%d",&m);
- for(int i=1;i<=m;i++)
- {
- int x; scanf("%d",&x);
- int t=n/x; ans^=(t<=Q)?sg[t]:fsg[n/t];
- }
- if(ans) puts("Yes"); else puts("No");
- }
- }
HAOI2015 泛做的更多相关文章
- codeforces泛做..
前面说点什么.. 为了完成日常积累,傻逼呵呵的我决定来一发codeforces 挑水题 泛做.. 嗯对,就是泛做.. 主要就是把codeforces Div.1的ABCD都尝试一下吧0.0.. 挖坑0 ...
- 学记笔记 $\times$ 巩固 · 期望泛做$Junior$
最近泛做了期望的相关题目,大概\(Luogu\)上提供的比较简单的题都做了吧\(233\) 好吧其实是好几天之前做的了,不过因为太颓废一直没有整理-- \(Task1\) 期望的定义 在概率论和统计学 ...
- 历年NOIP水题泛做
快noip了就乱做一下历年的noip题目咯.. noip2014 飞扬的小鸟 其实这道题并不是很难,但是就有点难搞 听说男神错了一个小时.. 就是$f_{i,j}$表示在第$i$个位置高度为$j$的时 ...
- LCT裸题泛做
①洞穴勘测 bzoj2049 题意:由若干个操作,每次加入/删除两点间的一条边,询问某两点是否连通.保证任意时刻图都是一个森林.(两点之间至多只有一条路径) 这就是个link+cut+find roo ...
- 基尔霍夫矩阵题目泛做(AD第二轮)
题目1: SPOJ 2832 题目大意: 求一个矩阵行列式模一个数P后的值.p不一定是质数. 算法讨论: 因为有除法而且p不一定是质数,不一定有逆元,所以我们用辗转相除法. #include < ...
- 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做
题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...
- FFT与多项式、生成函数题目泛做
题目1 COGS 很强的乘法问题 高精度乘法用FFT加速 #include <cstdlib> #include <iostream> #include <algorit ...
- 二维计算几何基础题目泛做(SYX第一轮)
题目1: POJ 2318 TOYS 题目大意: 给一个有n个挡板的盒子,从左到右空格编号为0...n.有好多玩具,问每个玩具在哪个空格里面. 算法讨论: 直接叉积判断就可以.注意在盒子的边界上面也算 ...
- 生成树题目泛做(AD第二轮)
题目1: NOI2014 魔法森林 LCT维护MST.解题报告见LOFTER #include <cstdio> #include <iostream> #include &l ...
随机推荐
- 魔术方法__sleep 和 __wakeup
感觉序列化和反序列化用得倒是比较少了,而json_encode和json_decode用得相对多,都是转化成串,进行入库.传输等.json更方便,但是序列化和反序列化结合这两个魔术方法使用倒还行< ...
- android px,dp,sp大小转换工具
package com.voole.playerlib.util; import android.content.Context; /** * Android大小单位转换工具类<br/> ...
- UML 用例图、顺序图、状态图、类图、包图、协作图、流程图
用例图.顺序图.状态图.类图.包图.协作图 面向对象的问题的处理的关键是建模问题.建模可以把在复杂世界的许多重要的细节给抽象出.许多建模工具封装了UML(也就是Unified Modeling La ...
- angular源码分析:angular中入境检察官$sce
一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...
- (四)新建Maven项目
我们以简单的helloworld来作为入门的实例,有些人说掌握了helloworld你就掌握了这门技术的一半了,对于maven来说,你掌握helloworld,你可能还稀里糊涂的. 1.从maven模 ...
- parawork平台介绍
ParaWork软件项目估算平台---科学估算项目,让管理更简单 ParaWork软件项目估算平台是由北京软件造价评估技术创新联盟与北京科信深度科技有限公司联合开发.维护的软件项目估算工具,为会员免 ...
- Provider:SSL Provider,error:0-等待的操作过时
今天一同事使用SSMS 2012 连接数据库时,遇到了"provider:SSL Provider,error:0-等待的操作过时",搜索了一下,遇到一哥 们也遇到这个问题:SQL ...
- YourSQLDba设置共享路径备份
YourSQLDba可以将数据库备份到网络路径(共享路径),这个也是非常灵活的一个功能,以前一直没有使用过这个功能,最近由于一个需求,于是我测试了一下YourSQLDba备份到网络路径,中间遇到了一些 ...
- asp.net signalR 专题—— 第四篇 模拟RPC模式的Hub操作
在之前的文章中,我们使用的都是持久连接,但是使用持久连接的话,这种模拟socket的形式使用起来还是很不方便的,比如只有一个唯一的 OnReceived方法来处理业务逻辑,如下图: protected ...
- 浅谈Java中的Set、List、Map的区别(转)
对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操作数目不固定的一组数据. 所有的JAVA集合都位于 java ...