陈题记录
5 Solved.
NOI2014
起床困难综合症
老早做的,因为位运算对于每一位都是独立的,那么先执行所有操作再计算最大效果即可.
魔法森林
我们把边权先按a排序(递增),这保证了对于前面的a总是最优的.每次加边,如果成环删去环上最大的边.实现技巧就是将边也看成点处理,这样就可以拿来一起link-cut了.
#include <cstdio>
#include <algorithm>
#define rg register
template<class T> inline void swp(T& a,T& b){ T x=a; a=b,b=x; }
inline void tensen(int& a,int b){ if(b<a) a=b; }
struct edge{ int f,t,a,b; } e[100010];
struct data{ int v,e; } empty=(data){0,0};
struct node;
node *null_node;
int n,m;
struct node{
node *ch[2],*fa;
data hr,mx;
node *top;
bool revf;
inline void rev(){
revf^=1; swp(ch[0],ch[1]);
}
inline void pd (){
if(revf){
ch[0]->rev(),ch[1]->rev(),revf=0;
}
}
inline void pu (){
if(ch[0]->mx.v > ch[1]->mx.v) mx=ch[0]->mx; else mx=ch[1]->mx;
if(hr.v > mx.v) mx=hr;
}
inline void rot(rg bool f){
node *fx=fa;
top=fx->top; fx->pd(), pd();
(fa=fx->fa)->ch[fx->fa->ch[1]==fx]=this;
(fx->ch[f]=ch[!f])->fa=fx;
(ch[!f]=fx)->fa=this;
fx->pu();
}
inline void spl(rg bool f=0){
node *fx=fa;
for(pd();fx!=null_node;fx=fa){
if(fx->fa==null_node) rot(fx->ch[1]==this); else
if((fx->fa->ch[1]==fx)==(f=(fx->ch[1]==this))){
fx->rot(f),rot(f);
}else rot(f),rot(!f);
}
}
inline void exp(node *p=null_node){
spl(); if(ch[1]!=null_node) ch[1]->top=this,ch[1]->fa=null_node;
(ch[1]=p)->fa=this; pu();
}
} tr[150030];
#define init1 null_node=tr;
#define beg init1
inline node*acc(node *x){
for(x->exp();x->top;x=x->top) x->top->exp(x);
return x;
}
inline void lnk(node *x,node *y){ (x=acc(x))->rev(); x->top=y; }
inline void cut(node *x,node *y){ x->exp(),y->exp(); if(x->top==y) x->top=NULL; if(y->top==x) y->top=NULL; }
struct rslt{ bool h; data r; };
inline rslt chk(node *x,node *y){
acc(x); data res=empty; node *A = acc(y);
if(A->ch[1]!=null_node) if(A->ch[1]->mx.v > res.v) res=A->ch[1]->mx;
node *B = acc(x); if(A!=B) return (rslt){0,res};
if(B->ch[1]!=null_node) if(B->ch[1]->mx.v > res.v) res=B->ch[1]->mx;
if(A->hr.v > res.v) return (rslt){1,A->hr}; else return (rslt){1,res};
}
inline bool cmp(const edge& a,const edge& b){ return a.a < b.a; }
inline void wrk(){
beg
int x,y;
scanf("%d%d",&n,&m);
for(int i=1,a,b;i<=m;++i){
scanf("%d%d%d%d",&n,&m,&a,&b);
e[i]=(edge){x,y,a,b};
if(x==y) --i,--m;
} std::sort(e+1,e+m+1,cmp);
for(int i=0;i<=n;++i) tr[i]=(node){{null_node,null_node},null_node};
int ans=1<<30,t; node *cur, *P=tr, *E=tr+n; rslt R;
for(int i=1;i<=m;++i){
if(e[i].a >= ans) break;
*(cur=E+i)=(node){{null_node,null_node},null_node,(data){e[i].b,i}};
R=chk(P+e[i].f,P+e[i].t); if(R.h){if(R.r.v > e[i].b){
t=R.r.e;
cut(P+e[t].f,E+t),cut(P+e[t].t,E+t);
lnk(P+e[i].f,cur),lnk(P+e[i].t,cur);
}}else
lnk(P+e[i].f,cur),lnk(P+e[i].t,cur);
if(e[i].a!=e[i+1].a) if((R=chk(P+1,P+n)).h) tensen(ans,R.r.v+e[i].a);
}
if(ans<(1<<30)) printf("%d\n",ans); else printf("-1\n");
}
int main(){
wrk();
return 0;
}
动物园
可以推广到回文树上,见CC PALPROB.
#include <cstdio>
#include <cstring>
#define maxn 1000005
char s[maxn];
int fail[maxn],hfail[maxn],dep[maxn];
int main(){
//can be applied to palindrome trees CC http://www.codechef.com/problems/PALPROB
int a;
scanf("%d",&a);
while(~scanf("%s",s+1)){
int len=strlen(s+1);
dep[1]=1;
int ans=1;
for(int i=2;i<=len;++i){
int j=fail[i-1];
while(s[j+1]!=s[i] && j) j=fail[j];
if(s[j+1]==s[i]) fail[i]=j+1; else fail[i]=0;
dep[i]=dep[fail[i]]+1;
j=hfail[i-1];
while((s[j+1]!=s[i] || (((j+1)<<1) > i)) && j) j=fail[j];
if(s[j+1]==s[i]) hfail[i]=j+1; else hfail[i]=0;
ans=(long long)ans*(dep[hfail[i]]+1)%1000000007;
}
printf("%d\n",ans);
}
return 0;
}
随机数生成器
都是些什么鬼题目...
大暴力,每次\(\overline{O\left(1\right)}\)判断能否加进一个点,如果要加入\(\overline{O\left(n\right)}\)修改.总时间复杂度\(\overline{O\left(nm+n^2\right)}\).
#include <cstdio>
#include <algorithm>
int per[25000010],rep[25000010],l[5010],r[5010];
int x,a,b,c,d;
int n,m,q;
#define rnd (x=(((long long)a*x+b)*x+c)%d)
inline void ge(){
scanf("%d%d%d%d%d",&x,&a,&b,&c,&d);
scanf("%d%d%d",&n,&m,&q);
int mn=n*m;
for(int i=1;i<=mn;++i) per[i]=i;
for(int i=1;i<=mn;++i){
int r=rnd%i+1;
if(r==i) continue;
std::swap(per[i],per[r]);
}
for(int i=0,a,b;i<q;++i) scanf("%d%d",&a,&b),std::swap(per[a],per[b]);
for(int i=1;i<=mn;++i) rep[per[i]]=i-1;
}
int main(){
ge();
int cnt=0,mn=m*n;
for(int i=0;i<=m;++i) r[i]=n+1;
for(int i=1;i<=mn;++i){
if(cnt==n+m-1) break;
int x=rep[i]/m+1,y=rep[i]%m+1;
if(l[y]<=x && x<=r[y]){
printf("%d ",i);
++cnt;
for(int j=y-1;j && r[j]>x;--j) r[j]=x;
for(int j=y+1;j<=m && l[j]<x;++j) l[j]=x;
}
}
return 0;
}
购票
由于凸包维护时求斜率的double值函数打成int值函数而调了好长时间...
第一次写点分治,第一次写斜率优化DP.(我好弱啊...)其实是对着prwang代码写的..
感觉点分治写法好巧妙啊...由于这题是在链上推公式所以不需要虚点..
题解感觉要以后写了..这题我只是A掉了而已..
WC 2013
糖果公园
据说是树上带修改莫队,事实上是树上带修改莫队.
第一次写,感觉这个挺神奇的..
树上可以用缩减的DFS序维护(出入节点counter).