NOI2014 部分题解
感觉NOI2014的一些题目也是比较好做的...
但是笔者往往有思路却没有想清楚就开始搞了...这样还是不太好..
Day1
T1 起床困难综合征 (我感觉这题应该叫综合征不是综合症...) ac通道
让你从[0...m]中选一个数使得其经过 (&xi或|xi或^xi) 之后的值最大。
记得冬令营有道试机题好像就是这样吧...然后机智的TB感觉十分自然的就想到了根据二进制的每一位来贪心弄一下就好了。
大致思路就是:从最高位开始,看一下这一位设为0和设为1有什么区别。
如果不管你设什么这一位运算完之后都为0或者为1,那就真·不管了...
如果发现设为1有值而设为0没有值,那就设为1吧。但是这个值不能超过m...
很机智的样子。
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; inline int in(){
int x=;char ch=getchar();
while(ch>'' || ch<'') ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return x;
} const int maxn=; struct Node{
int tp,dt;
}s[maxn]; int n,m;
char ord[]; int calcu(int x){
int tx=x; x=<<x;
for(int i=;i<=n;i++){
if(s[i].tp==) x=x&s[i].dt;
else if(s[i].tp==) x=x|s[i].dt;
else x=x^s[i].dt;
}
return x&(<<tx);
} int main(){
#ifndef ONLINE_JUDGE
freopen("sleep.in","r",stdin);
freopen("sleep.out","w",stdout);
#endif n=in(),m=in();
for(int i=;i<=n;i++){
scanf("%s%d",ord,&s[i].dt);
if(ord[]=='A') s[i].tp=;
else if(ord[]=='O') s[i].tp=;
else s[i].tp=;
} int ans=; int tmp=;
for(int i=;i<=n;i++){
if(s[i].tp==) tmp=tmp&s[i].dt;
else if(s[i].tp==) tmp=tmp|s[i].dt;
else tmp=tmp^s[i].dt;
}
for(int i=;i>=;i--){
if(tmp & (<<i)){
ans+=<<i; continue;
}
if(calcu(i) && m>(<<i))
ans+=<<i,m-=(<<i);
} printf("%d",ans);
return ;
}
T2 魔法森林 ac通道
给你n个点m条边,每条边有2个权值,然后要求找一条路从1到n使得这条路上的两个权值的最大值加起来最小。
我记得写过一篇题解的...
然后就是复习一遍LCT的实现咯。
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; inline int in(){
int x=;char ch=getchar();
while(ch>'' || ch<'') ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return x;
} const int maxn=; struct Node{
int l,r,f;
int dt,mx,lc;
bool rt,rv;
Node(){rt=true;}
void trans(){swap(l,r);}
}s[maxn*]; struct Edge{
int u,v,a,b;
}e[maxn]; bool cmp(const Edge &A,const Edge &B){
if(A.a!=B.a) return A.a<B.a; return A.b<B.b;
} int n,m;
int p[maxn*]; void update(int x);
void push_down(int x);
void Down_tag(int x);
void zig(int x);
void zag(int x);
void Splay(int x);
void Access(int x);
void Make_rt(int x);
void Link(int u,int v);
void Cut(int u,int v);
int Find(int x); int main(){
#ifndef ONLINE_JUDGE
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
#endif n=in(),m=in();
for(int i=;i<=m;i++){
e[i].u=in(),e[i].v=in(),e[i].a=in(),e[i].b=in();
if(e[i].u==e[i].v) i--,m--;
} int fx,fy,u,v,ans=0x3f3f3f3f; sort(e+,e+m+,cmp);
for(int i=;i<=n+m;i++) p[i]=i;
for(int i=;i<=n+m;i++) s[i].lc=i;
for(int i=;i<=m;i++){
u=e[i].u,v=e[i].v;
fx=Find(u),fy=Find(v);
if(fx!=fy){
s[i+n].dt=e[i].b;
Link(u,i+n),Link(v,i+n);
p[fx]=fy;
}
else{
Make_rt(u),Access(v),Splay(v);
if(s[v].mx>e[i].b){
int t=s[v].lc-n;
Cut(t+n,e[t].u),Cut(t+n,e[t].v);
s[i+n].dt=e[i].b;
Link(u,i+n),Link(v,i+n);
}
} if(Find()==Find(n)){
Make_rt();Access(n);Splay(n);
ans=min(ans,s[n].mx+e[i].a);
}
} if(ans==0x3f3f3f3f) ans=-;
printf("%d",ans);
return ;
} void update(int x){
s[x].mx=s[x].dt,s[x].lc=x;
if(s[x].l && s[s[x].l].mx>s[x].mx) s[x].mx=s[s[x].l].mx,s[x].lc=s[s[x].l].lc;
if(s[x].r && s[s[x].r].mx>s[x].mx) s[x].mx=s[s[x].r].mx,s[x].lc=s[s[x].r].lc;
} void push_down(int x){
if(s[x].rv){
s[x].trans();
if(s[x].l) s[s[x].l].rv^=;
if(s[x].r) s[s[x].r].rv^=;
s[x].rv=;
}
} void Down_tag(int x){
if(!s[x].rt) Down_tag(s[x].f);
push_down(x);
} void zig(int x){
int y=s[x].f;s[x].f=s[y].f;
if(s[y].rt) s[x].rt=true,s[y].rt=false;
else{
if(y==s[s[y].f].l) s[s[y].f].l=x;
else s[s[y].f].r=x;
}
s[y].l=s[x].r;
if(s[x].r) s[s[x].r].f=y;
s[x].r=y,s[y].f=x;
update(y);
} void zag(int x){
int y=s[x].f;s[x].f=s[y].f;
if(s[y].rt) s[x].rt=true,s[y].rt=false;
else{
if(y==s[s[y].f].l) s[s[y].f].l=x;
else s[s[y].f].r=x;
}
s[y].r=s[x].l;
if(s[x].l) s[s[x].l].f=y;
s[x].l=y,s[y].f=x;
update(y);
} void Splay(int x){
Down_tag(x);
while(!s[x].rt){
int y=s[x].f;
if(s[y].rt){ if(x==s[y].l) zig(x);
else zag(x);}
else{
int z=s[y].f;
if(y==s[z].l){ if(x==s[y].l) zig(y),zig(x);
else zag(x),zig(x);}
else{ if(x==s[y].r) zag(y),zag(x);
else zig(x),zag(x);}
}
}
update(x);
} void Access(int x){
for(int last=;x;x=s[last=x].f){
Splay(x);
s[s[x].r].rt=true;
s[s[x].r=last].rt=false;
update(x);
}
} void Make_rt(int x){
Access(x); Splay(x); s[x].rv=;
} void Link(int u,int v){
Make_rt(u); s[u].f=v;
} void Cut(int u,int v){
Make_rt(u); Access(v); Splay(v);
s[u].rt=true; s[u].f=s[v].f;
s[v].l=s[v].f=;
} int Find(int x){
int r=x,pre;
while(r!=p[r]) r=p[r];
while(r!=x)
pre=p[x],p[x]=r,x=pre;
return r;
}
D2
T1 动物园 ac通道
给你一个串,让你求每个位置的满足不重复的相同前缀和后缀的个数。
唔,比较容易想到的就是一种模拟的方法。
每个位置都沿着next指针往后跳,看能在i/2之前跳多少次。
但是这样的话是很容易卡你的,比如aaaaaaaaaaa,让你每次next都只跳一步= =这样的话就变成n^2了。
然后比较好像到的就是我直接记忆化一下累加的结果。使用记忆化的话,你可以只要跳到第一个满足条件的位置就可以了。
但是你跳到i/2前面的过程如果仍然使用模拟的话就会超时,理由同上。那么怎么求呢?
笔者太傻了...没有想到直接沿着上一个的位置来就好了...和你求kmp的过程是完全一样的,只是这个的前引指针不是指向最长位置了,而是<i/2的最长位置。
然后你后面的指针往后移动的时候,前面的指针还是可以和以前的一样跳。这样的话就是O(n)的了。
感觉对kmp的思路比较清晰的话对这题是很有帮助的。
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; typedef long long ll;
const int maxn=;
const int mod=1e9+; int n,len;
int next[maxn],cnt[maxn];
char ch[maxn]; void get_next(){
int first=-,last=;
next[]=-;
while(last<len){
if(first==- || ch[last]==ch[first]){
first++,last++;
next[last]=first;
cnt[last]=cnt[first]+;
}
else
first=next[first];
}
} int get_cnt(){
int ans=,first=-,last=;
while(last<len){
if(first==- || ch[last]==ch[first]){
first++,last++;
while((first<<)>last) first=next[first];
ans=(ll)ans*(cnt[first]+)%mod;
}
else
first=next[first];
}
return ans;
} int main(){
#ifndef ONLINE_JUDGE
freopen("zoo.in","r",stdin);
freopen("zoo.out","w",stdout);
#endif int tmp;
ll ans; scanf("%d",&n);
while(n--){
scanf("%s",ch);
len=strlen(ch);
get_next();
printf("%d\n",get_cnt());
} return ;
}
T2 随机数生成器 ac通道
告诉你一种生成随机数的方法,告诉你一种通过随机数生成排列的方法。然后把这个排列扔在一个n*m的地图上,让你选择一条从(1,1)到(n,m)的路径,使得这条路径上的数字从小到大排序之后得到的字典序最小。
首先的那个部分可以模拟= =。但是你需要控制好空间,比如说随机数你就没有必要求出来,直接用来搞排列之类的...然后你那个地图也不要做出来,直接搞一个一维的挺好。
然后就到了怎么找到这样一条路径了...感觉贪心的思路很自然。笔者趁机来秀一下gif[第一次做题解动图...可能没怎么画的好QAQ]。
做了一个样例的求法...是不是很良心啊....
好吧:样例不良心,但是笔者良心2333333
大致的思路就是如此了,按从小到大的顺序,选择了之后将(1,1)到(x-1,y)的矩阵保留,把(x+1,y)到(n,n)的矩阵保留,剩余的删除。
然后直到只剩下一条通路为止。
首先我们要能找到每个点所在的位置,由于之前已经用了100MB了,那么我们最多再开一个...那就记录一个lc[T[i]]=i;然后把i%m和/m处理好了。
但是怎么把矩阵保留|删除呢?...是不是要用二维树状数组呢?但是二维树状数组也会超时啊...因为你要进行判定的话,那么就比较恶心...每个点都要判断一下...就超时了
那么我们直接暴力修改就好了。
每行记录一个可以放的范围l[i]和r[i],然后每找到一个可以用的点就去暴力修改其它行的有关数据。
由于需要修改的点只有n+m-1个,那么每次修改的复杂度即使是O(n)的也只有n^2;而判定是否合格每个位置都是O(1)的。
最后复杂度还是N^2的但是常数很大而已啦...
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; inline int in(){
int x=;char ch=getchar();
while(ch>'' || ch<'') ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return x;
} const int maxn=;
typedef long long ll; int n,m,nm,q;
int x0,a,b,c,d;
int T[maxn*maxn],rk[maxn*maxn];
int l[maxn],r[maxn]; int main(){
#ifndef ONLINE_JUDGE
freopen("random.in","r",stdin);
freopen("ramdom.out","w",stdout);
#endif int x,u,v,tmp,x1,y1,cnt=;
bool flag=; x0=in(),a=in(),b=in(),c=in(),d=in();
n=in(),m=in();
nm=n*m;
for(int i=;i<=nm;i++) T[i]=i; x=x0;
for(int i=;i<=nm;i++){
x=((ll)a*x%d*x%d+(ll)b*x%d+c)%d;
tmp=T[i],T[i]=T[x%i+],T[x%i+]=tmp;
//swap(T[i],T[x%i+1]);
} q=in();
for(int i=;i<=q;i++){
u=in(),v=in();
tmp=T[u],T[u]=T[v],T[v]=tmp;
//swap(T[u],T[v]);
}
for(int i=;i<=nm;i++) rk[T[i]]=i;
for(int i=;i<=n;i++) l[i]=,r[i]=m;
for(int i=;i<=nm;i++){
x1=rk[i]/m+,y1=rk[i]%m;
if(!y1) x1--,y1=m; if(y1>r[x1] || y1<l[x1]) continue;
else{
if(flag) printf(" %d",i);
else flag=,printf("%d",i); for(int j=;j<x1;j++) if(r[j]>y1) r[j]=y1;
for(int j=x1+;j<=n;j++) if(l[j]<y1) l[j]=y1;
cnt++;
if(cnt==n+m-) break;
}
} return ;
}
NOI2014 部分题解的更多相关文章
- 【KMP】洛谷P2375 [NOI2014]动物园 题解
一开始的方向应该对了,但是没有想到合理的优化还是没写出来…… 题目描述 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己 ...
- BZOJ3670 & 洛谷2375 & UOJ5:[NOI2014]动物园——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3670 https://www.luogu.org/problemnew/show/P2375#su ...
- NOI2014题解
起床困难综合症(BZOJ 3668) 送分题,直接从高位向低位贪心. 魔法森林(BZOJ 3669) 一个容易想到的办法就是枚举A的最大值,以B作为权值求最小生成树.暴力的话要T的.如果从小到大枚举A ...
- NOI2014魔法森林题解报告
题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2,3,-,n,边标号为 1,2,3,-, ...
- 【题解】洛谷P2375 [NOI2014] 动物园(KMP)
洛谷P2375:https://www.luogu.org/problemnew/show/P2375 思路 这道题可以说是完全刷新了本蒟蒻对KMP的理解 感觉对next数组的理解上升到一个新的高度 ...
- BZOJ3669:[NOI2014]魔法森林——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3669 https://www.luogu.org/problemnew/show/P2387 为了得 ...
- 【题解】 UOJ #2. 【NOI2014】起床困难综合症
传送门 不是很简单? 考虑一下这个数的二进制位是什么,要么是1,要么是0. 然后怎么做? 因为一开始可以选0~m的数,那么二进制为中全是0的肯定是可以选的. 接着考虑全是1的怎么选? 如果全都是1的而 ...
- BZOJ3668:[NOI2014]起床困难综合症——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3668 https://www.luogu.org/problemnew/show/P2114 21世 ...
- 【题解】NOI2014购票
实际上是一个不完美算法……cogs上面A不掉(爆栈啦).感谢机房大佬PPY的指点,现在也写出来供大家参考参考,理解起来应该是比较简单的一种. 我们首先get出斜率优化方程: \(dp[v] = dis ...
随机推荐
- Spring 笔记(三)Bean 装配
前言 Spring 有两大核心,也就分成两份笔记分别记录. 其一是管理应用中对象之间的协作关系,实现方式是依赖注入(DI),注入依赖的过程也被称为装配(Wiring). 基于 JavaConfig 的 ...
- 替换localhost:8080(假域名,本地使用)
1. 更改servers 的端口号为 80 (默认 8080),此时就不用再输入 8080了. 2. 找到 C:\Windows\System32\drivers\etc 下的 hosts 文件,用记 ...
- BZOJ 2243 染色(树链剖分好题)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 7971 Solved: 2990 [Submit][Stat ...
- python下载链接内容
下面代码下载京东注册码,可接收参数num dir 可以将连接构造成其它网址,比如移动联通网上营业厅的验证码都是固定网址+13位时间戳的结构. #!/usr/bin/python #code utf-8 ...
- 什么是SetUID
1. 什么是SetUID 我们知道,在linux的命令行下执行“ps”命令时,就会列出当前系统中的所有进程,在其中可以看到每个进程都和用户的真实id关联,实际上,Linux中的每个进程还跟一个称为有效 ...
- java自定义类型 比较排序 Comparator接口
String service_time = "6:00:00,7:00:00,8:00:00,9:00:00,10:00:00,11:00:00,12:00:00,13:00:00,14:0 ...
- pagination用法
pagination用法: 1.html 要用两层div <script src="${app }/pc/js/media/pagination.js"></s ...
- 转:ListView中getView的工作原理
ListView中getView的工作原理: [1]ListView asks adapter “give me a view” (getView) for each item of the list ...
- 2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest(solved 8/11)
这套题似乎是省选前做的,一直没来写题解---补上补上>_< 链接:http://codeforces.com/gym/101147 一样先放上惨不忍睹的成绩好了--- Problem A ...
- HDU1536&&POJ2960 S-Nim(SG函数博弈)
S-Nim Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u Submit Status ...