2014 Multi-University Training Contest 2
官方解题报告:http://blog.sina.com.cn/s/blog_a19ad7a10102uyet.html
ZCC Loves Intersection
ZCC Loves COT
首先考虑一维下的版本。(数列,区间加,区间和)
显然可以使用线段树,但是线段树推广到高维度的难度较大。
针对本题先修改再询问的特点,我们可以在修改时只保存差分后的数组。
在处理询问前求前缀和还原原数列。之后再求一次前缀和就可以做到O(1)回答询问了。
现在试图把它推广到二维。(三角形,子三角形加,子三角形和)
如果朴素地对每一行应用一维的差分法,最后得到的标记会像下面一样:
其中+1标记和-1标记都是连续的一段。
标记也是一种值,所以可以对标记打标记!
于是我们将所有的+1标记按从右上到左下做差分,将所有的-1标记按从左上到右下做差分。
这样每个操作实际上只需要在两个数组中修改四个值,最后利用这两个数组还原原来的标记,利用标记还原原数阵。前缀和的计算也是类似,只不过第二维的前缀和要从两个方向各算一遍。
类似地,只需要4个数组就可以表示三维情况下的所有标记,经过三轮不同方向上的求前缀和就可以得到原四面体,前缀和的计算也需要4个数组。这样单操作/单询问要拆成8个,是O(1)的,复杂度是O(N^3+M+Q)。
ZCC Loves RPG
在程序的每一个位置,都存在若干条形如a[x]>=v或!(a[x]>=v)的限制。它们给每个a[i]确定了一个上界和一个下界。显然,我们应当让a[i]尽量小,因此我们可以令a[i]恰取到它的下界。
那么,考虑一对上下界数列Ui, Di,当前语句可以被执行到的条件就是:
随着我们分析程序的过程,一些位置的下界会发生变化,我们需要随时重新计算这个最大非零子段和,这就是说,我们需要对一个数列支持单点修改和查询最大非零子段和。这是一个线段树的经典应用,这里不再赘述。
下面考虑如何分析程序。
首先需要实现一个词法分析器:它接受字符串作为其输入,每次返回一个记号(常量,符号或标识符等)。这部分可以按照写读入优化的方法来写。
然后就到了对记号流进行分析的步骤,这一步的做法有很多,这里只讲一下std的做法。
首先将game(n, k)读入,获取n, k的值,同时建立线段树。
清空两个栈,这两个栈一个用于保存程序结构(称为栈P),一个用于保存Ui和Di的变化便于之后撤销(称为栈Q)。
读入左花括号,向栈P中压入一个B符号,B符号声明当前语句处于一对未闭合的花括号内,当栈P顶是B符号时,可以向这个花括号内追加语句。
随后重复以下过程直至栈P空。
检查栈P的栈顶:
若为B:从词法分析器取得下一个记号。
若为右花括号:弹出B。(闭合花括号)
否则:把这个记号“塞回去”,向栈P压入S符号。(追加语句)
若为S:弹出S,从词法分析器取得下一个记号。
若为左花括号:向栈P压入B符号。(新建块)
若为cg:读入整个cg语句,查询当前是否可达,更新答案。
若为if:读入if语句的第一句,读入x, v。向栈P先后压入I符号,T符号和S符号。向栈Q先后压入!(a[x]>=v)和a[x]>=v,在线段树上做a[x]>=v的修改。
若为T:弹出T,弹出栈Q栈顶元素,撤销它的修改。从词法分析器取得下一个记号:
若为else:应用栈Q栈顶元素(之前加入了但没有应用的!(a[x]>=v))的修改。向栈P压入S符号。
否则:把记号塞回去。弹出栈Q栈顶元素,弹出栈P栈顶元素(必定是I符号)。
若为I:弹出I,弹出栈Q栈顶元素,撤销它的修改。
B,S,T,I四个符号的意思分别是:块,语句,Then结束,整个If结束。
最后输出答案。
ZCC Loves Minecraft
所求的S即为当前点集的正交凸包。
参见en.wikipedia.org/wiki/Orthogonal_convex_hull的相关介绍。直观地看正交凸包是左上、右上、左下、右下四段折线构成的多边形,每条边都与坐标轴平行。求已知点集的正交凸包,可以先找出最上、最下、最左、最右的点。求右上方的一段折线,可以从最上面的点开始,每次找当前点右边的点中最上面的点,与当前点L形连接,作为新的当前点,不断重复直到选到最右边的点。这一过程实现非常简单,只要先按横坐标排序,然后扫描一遍并维护纵坐标最大值即可。其它三段的求法是类似的,而且可以通过旋转进行转化。那么对于动态加点的问题,可以用4棵平衡树(实现用STL即可)分别维护四段折线。插入点时尝试将其分别插入四段折线的相应位置,若在当前折线外部需要更新折线,并计算面积的增量。以右上折线为例,需要不断判断新点左边的点是否在新点下方,若是则删除。由于每个点最多被插入一次删除一次,总的时间复杂度是O(nlogn)。边界情况需要一定的特判。
ZCC Loves words
这道题我们可以先对单词建出AC自动机。然后在AC自动机上进行计数(dp)。F[i][j]表示当前长度第i位,当前在AC自动机的j号节点。我们考虑主动转移,如果j号节点在接受c这个字符后到了第k个节点,那么F[i+1][k]+=F[i][j]*Get。其中Get表示在第k个节点能乘上的数字。
我们来分析一下Get。,那么如果没有+i这个东西,我们就可以建出矩阵,然后直接快速幂+矩阵乘法。但是有了+i的话,每个矩阵都不同,但是事实上P=179*173*163,这其中的质数非常的小,然后就是乱搞的部分了,i Mod Pi就是O(Pi)的循环,于是我们建出Pi个矩阵,然后对于L/Pi的部分快速幂+矩阵乘法,对于L Mod Pi的部分暴力矩阵乘法即可。对于每一个质数得到的答案,利用中国剩余定理就可算出最后的答案。复杂度大概是O(Pi*tot^3 + log(L)*tot^3)。
如果有更优的做法欢迎指教。
ZCC Loves cards
ZCC Love ranklist
第一问:
当k=1的时候答案显然为n-1。
当k=2t(t∈Z*)时答案显然为0。把比赛分成两两一组,每组和为n+1即可。
当k=2t+1(t∈Z*)时先两两一组到只剩3个。n为偶数时答案显然不能为0,只能做到1。奇数时则可以做到。一种解决办法是:
n为奇数 |
1 |
4 |
7 |
n为偶数 |
1 |
4 |
6 |
2 |
5 |
5 |
2 |
5 |
4 |
||
3 |
6 |
3 |
3 |
6 |
2 |
||
4 |
7 |
1 |
4 |
1 |
5 |
||
5 |
1 |
6 |
5 |
2 |
3 |
||
6 |
2 |
4 |
6 |
3 |
1 |
||
7 |
3 |
2 |
第二问:
先观察进步指数的性质:由于NewRank=OldRank的时候进步指数=0所以只能出现一次所以不应该使用。当NewRank!=OldRank的时候两个进步指数相等当且仅当NewRank和OldRank都相等,两个进步指数为相反数当且仅当NewRank1=OldRank2,OldRank1=NewRank2。
总共能出现n*(n-1)+1种不同的进步指数,而且n>1,所以每种进步指数(除了0)都会出现。并且进步指数为相反数的一对只能出现在同一场考试中。所以n为奇数时显然无解。
当n为偶数时,注意到每场考试实际上是将考生两两组队n-1轮且不重复。于是使用循环赛构造算法即可。
循环赛构造算法:http://www.doc88.com/p-694165485213.html
ZCC Love march
我们用set维护当前的士兵位置,合并的时候将每个士兵暴力合并到该位置,即删掉原位置士兵并使目标位置size+=原位置size。每次移动的时候将原位置size--并在新位置新建一个size为1的士兵。这样最多只会有n+移动数 的士兵,每个士兵只会合并一次,所以时间复杂度为O(nlogn)。实现的时候为了记录每个点的坐标可以用并查集维护所在的块。
ZCC Love traffic lights
首先考虑如果是一般图的话怎么做。可以证明存在一个最优解在某一条边上卡着时间进去或者卡着时间出来。因为如果不这样的话可以将每个点的时间往后推直到卡着时间。所以只要对在每个点上卡时的情况进行判断。
枚举了某个点的到达时间以后那么接下来我们可以使用最短路算法求出到终点的最早时间和从起点出发的最晚时间。具体实现的时候可以对每个点开8个状态记录从哪个方向进入和是否闯过红灯。
ZCC loves Army
Solution:
可以发现上司和下属之间的关系可以构成一棵树,考虑三种操作。
交换下属:为了使交换下属的时候改变的边变少,可以用左儿子右兄弟的方式表示这棵树。那么交换时只需要改变至多4条边。可以用LCT维护。
传送信息:求从x传信息到y所需要的中介人的最少个数。令x为深度较大的一个点,这条路径就是x向上传到和y同一层,再水平传送。可以把编号为1的儿子的权值赋值为1,求x,y简单路径上的权值和。
发送指令:求x可以收到几个士兵发出的指令。表现在左儿子右兄弟的树上即为求该点到根之间的点个数。
Postscript:
为了方便,可以给每个点加一个编号为0的虚孩子,可以避免一些细节问题。
交换下属的时候找孩子可以对每个点开一个平衡树,也可以直接用LCT里的Splay。
ZCC loves Codefires
考察序列中相邻的两题i, j(i在前)。交换它们后,解出它们之前的题目所带来的时间对答案的贡献是不变的,它们对它们后面的题目的贡献也是不变的,其他题目之间对答案的贡献自然也是不变的。唯一的变化就是,原来的EiKj一项变成了EjKi一项。那么,为了使答案变优,需要满足的条件是EjKi≤EiKj。也即Ei/Ki≥Ej/Kj。
那么,最优解序列Ai一定满足,EAi/KAi是递增的。
排序一遍即可。
ZCC Loves Intersection http://acm.hdu.edu.cn/showproblem.php?pid=4873
公式见题解。我没推。
import java.math.BigInteger;
import java.util.Scanner; class Main{
public static void main(String arg[]){
Scanner cin=new Scanner(System.in);
BigInteger n,fenzi,fenmu,tmp,gcd;
int d;
while(cin.hasNext()){
n=cin.nextBigInteger();
d=cin.nextInt();
tmp=n.add(BigInteger.valueOf(4));
fenzi=tmp.multiply(tmp);
fenzi=fenzi.multiply(BigInteger.valueOf(d));
fenzi=fenzi.multiply(BigInteger.valueOf(d-1));
fenmu=n.pow(d);
fenmu=fenmu.multiply(BigInteger.valueOf(18));
gcd=fenmu.gcd(fenzi);
fenzi=fenzi.divide(gcd);
fenmu=fenmu.divide(gcd);
if(!fenzi.equals(fenmu)){
System.out.println(fenzi+"/"+fenmu);
}
else {
System.out.println(1);
}
}
}
}
ZCC loves cards http://acm.hdu.edu.cn/showproblem.php?pid=4876
二进制暴力加一个剪枝。勉强过。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=;
int a[M];
int b[M];
bool vis[M];
int sum[M];
int main(){
int n,k,L;
while(~scanf("%d%d%d",&n,&k,&L)){
for(int i=;i<n;i++){
scanf("%d",&a[i]);
}
int all=<<n;
int ans=;
for(int i=;i<all;i++){
int tmp=i;
int num=;
while(tmp){
if(tmp&) num++;
tmp>>=;
}
if(num==k){
int lb=;
for(int j=;j<n;j++){
if((i>>j)&){
b[lb++]=a[j];
}
}
int big=<<k;
mt(vis,);
for(int j=;j<big;j++){
int add=;
for(int u=;u<k;u++){
if((j>>u)&) add^=b[u];
}
vis[add]=true;
}
int R=;
for(int j=L;j<M;j++){
if(!vis[j]) break;
R=j;
}
if(ans>=R) continue; //cut
sort(b,b+lb);
do{
for(int j=;j<k;j++){
b[j+k]=b[j];
}
sum[]=b[];
int k2=k+k;
for(int j=;j<k2;j++){
sum[j]=sum[j-]^b[j];
}
mt(vis,);
for(int u=;u<k;u++){
for(int v=u;v<k2&&v-u<k;v++){
int add=sum[v];
if(u->=) add^=sum[u-];
vis[add]=true;
}
}
int R=;
for(int j=L;j<M;j++){
if(!vis[j]) break;
R=j;
}
ans=max(ans,R);
}while(next_permutation(b,b+lb));
}
}
printf("%d\n",ans);
}
return ;
}
ZCC loves march http://acm.hdu.edu.cn/showproblem.php?pid=4879
数据要离散化,并查集,有点吊。
#include<cstdio>
#include<iostream>
#include<map>
#include<set>
using namespace std;
typedef __int64 LL;
typedef pair<LL,LL> pll;
const int mod=;
const int M=;
int f[M],sz[M],MXtot,MYtot,link[M];
LL lans;
struct Input {
LL x,y;
} a[M];
map<pll,LL>pos;
set<pll>PX[M],PY[M];
set<pll>::iterator it;
map<LL,int>MX,MY;
int getroot(int x) {
if(x==f[x])return x;
return f[x]=getroot(f[x]);
}
void ins(int id) {
pll now=make_pair(a[id].x,a[id].y);
if(pos[now]) {
sz[pos[now]]++;
f[id]=pos[now];
return;
}
pos[now]=id;
if(!MX[a[id].x]) MX[a[id].x]=++MXtot;
if(!MY[a[id].y]) MY[a[id].y]=++MYtot;
PX[MX[a[id].x]].insert(make_pair(a[id].y,id));
PY[MY[a[id].y]].insert(make_pair(a[id].x,id));
}
int main() {
int n,q,id;
LL m;
while(~scanf("%d%I64d",&n,&m)) {
for(int i=; i<=n; i++) {
f[i]=i;
sz[i]=;
link[i]=i;
}
for(int i=; i<=n; i++) {
scanf("%I64d%I64d",&a[i].x,&a[i].y);
ins(i);
}
scanf("%d",&q);
while(q--) {
char op[];
scanf("%s",op);
if(op[]=='Q') {
scanf("%d",&id);
id^=lans;
id=link[id];
int fa=getroot(id);
lans=;
LL X=a[fa].x;
LL Y=a[fa].y;
LL XX=MX[X];
LL YY=MY[Y];
LL pf,ps;
for(it=PX[XX].begin();it!=PX[XX].end();it++){
pf=it->first; //y
ps=it->second; //id
if(ps!=fa) {
LL dy=(pf-Y)%mod;
dy=dy*dy%mod;
lans=(lans+dy*sz[ps]%mod)%mod;
pos.erase(make_pair(X,pf));
PY[MY[pf]].erase(make_pair(X,ps));
sz[fa]+=sz[ps];
f[getroot(ps)]=fa;
}
}
PX[XX].clear();
PX[XX].insert(make_pair(Y,fa));
for(it=PY[YY].begin();it!=PY[YY].end();it++){
pf=it->first; //x
ps=it->second; //id
if(ps!=fa) {
LL dx=(pf-X)%mod;
dx=dx*dx%mod;
lans=(lans+dx*sz[ps]%mod)%mod;
pos.erase(make_pair(pf,Y));
PX[MX[pf]].erase(make_pair(Y,ps));
sz[fa]+=sz[ps];
f[getroot(ps)]=fa;
}
}
PY[YY].clear();
PY[YY].insert(make_pair(X,fa));
printf("%d\n",lans);
}
else {
LL y;
scanf("%d%I64d",&id,&y);
id^=lans;
int p=link[id];
sz[getroot(p)]--;
n++;
link[id]=n;
id=getroot(p);
a[n]=a[id];
f[n]=n;
sz[n]=;
pos.erase(make_pair(a[id].x,a[id].y));
if(op[]=='U') {
a[n].x-=y;
}
else if(op[]=='D'){
a[n].x+=y;
}
else if(op[]=='L'){
a[n].y-=y;
}
else if(op[]=='R'){
a[n].y+=y;
}
ins(n);
}
}
}
return ;
}
ZCC Loves Codefireshttp://acm.hdu.edu.cn/showproblem.php?pid=4882
推出一个优先关系,排序。
#include<cstdio>
#include<algorithm>
using namespace std;
typedef __int64 LL;
const int M=;
struct G{
int t,k;
friend bool operator <(G a,G b){
return a.t*b.k<a.k*b.t;
}
}g[M];
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<n;i++){
scanf("%d",&g[i].t);
}
for(int i=;i<n;i++){
scanf("%d",&g[i].k);
}
sort(g,g+n);
LL ans=,tmp=;
for(int i=;i<n;i++){
ans+=(tmp+g[i].t)*g[i].k;
tmp+=g[i].t;
}
printf("%I64d\n",ans);
}
return ;
}
end
2014 Multi-University Training Contest 2的更多相关文章
- HDU4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)
Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- hdu 4946 2014 Multi-University Training Contest 8
Area of Mushroom Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 2014 Multi-University Training Contest 9#11
2014 Multi-University Training Contest 9#11 Killing MonstersTime Limit: 2000/1000 MS (Java/Others) ...
- 2014 Multi-University Training Contest 9#6
2014 Multi-University Training Contest 9#6 Fast Matrix CalculationTime Limit: 2000/1000 MS (Java/Oth ...
- 2014 Multi-University Training Contest 1/HDU4861_Couple doubi(数论/法)
解题报告 两人轮流取球,大的人赢,,, 贴官方题解,,,反正我看不懂.,,先留着理解 关于费马小定理 关于原根 找规律找到的,,,sad,,, 非常easy找到循环节为p-1,每个循环节中有一个非零的 ...
- 2014 Multi-University Training Contest 1/HDU4864_Task(贪心)
解题报告 题意,有n个机器.m个任务. 每一个机器至多能完毕一个任务.对于每一个机器,有一个最大执行时间Ti和等级Li,对于每一个任务,也有一个执行时间Tj和等级Lj.仅仅有当Ti>=Tj且Li ...
- hdu 4937 2014 Multi-University Training Contest 7 1003
Lucky Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) T ...
- hdu 4941 2014 Multi-University Training Contest 7 1007
Magical Forest Time Limit: 24000/12000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Other ...
- hdu 4939 2014 Multi-University Training Contest 7 1005
Stupid Tower Defense Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/ ...
- hdu 4930 Fighting the Landlords--2014 Multi-University Training Contest 6
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4930 Fighting the Landlords Time Limit: 2000/1000 MS ...
随机推荐
- sql with as用法详解
一.WITH AS的含义 WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让 ...
- 在浏览器中打开本地应用(iOS)
在浏览器中点击跳转到本地应用的方法(如果本地没有安装的话) 然后在浏览器中输入tianxiang://就能打开这个应用了 ................省略 遇到一个12年还是初中的小朋友,
- ARM你必须知道的事儿——为啥“PC = PC + 8”?
为啥是“PC = PC + 8”: “PC = PC + 8”其实这样写容易让人蒙了.“PC = PC + 8”真正含义应该是: 执行处代码地址 = PC - 8: 也就是说,”PC指向的地址“领先“ ...
- (转)Yale CAS + .net Client 实现 SSO(1)
由于信息系统集成需要,最近研究了一下CAS.从网上找了不少资料,很多是针对Java平台的,为数不多的针对.net Client的文章往往片面的介绍某个方面,照着去做确会遇到大量的问题,特别是“重定向循 ...
- Linux 伙伴算法简介
本文将简要介绍一下Linux内核中的伙伴分配算法. Technorati 标签: 伙伴算法 算法作用 它要解决的问题是频繁地请求和释放不同大小的一组连续页框,必然导致在已分配 ...
- FTP 数字代码的意义
110 重新启动标记应答. 120 服务在多久时间内ready. 125 数据链路埠开启,准备传送. 150 文件状态正常,开启数据连接端口. 200 命令执行成功. 202 命令执行失败. 211 ...
- nginx配置多个网址
实战Nginx与PHP(FastCGI)的安装.配置与优化:http://ixdba.blog.51cto.com/2895551/806622 Nginx配置文件详细说明:http://www.cn ...
- 主引导记录MBR
作者:马 岩(Furzoom) (http://www.cnblogs.com/furzoom/)版权声明:本文的版权归作者与博客园共同所有.转载时请在明显地方注明本文的详细链接,未经作者同意请不要删 ...
- linux下dup/dup2函数的用法
系统调用dup和dup2能够复制文件描述符.dup返回新的文件文件描述符(没有用的文件描述符最小的编号).dup2可以让用户指定返回的文件描述符的值,如果需要,则首先接近newfd的值,他通常用来重新 ...
- Scrapy源码学习(一)
用Scrapy已经有一段时间了,觉得该是看一下源码的时候了.最开始用的时候还是0.16的版本,现在稳定版已经到了0.18.结合使用Scrapy的过程,先从Scrapy的命令行看起. 一.准备 下载源代 ...