20190803考试反思
这次考试就不骂自己了,毕竟骂了也没用。T1是水题。。用map手卡30分,我tm。。。。然后以为这就结束了,然后去改T2,T2WA40,我写的主席树但是修改是自己yy的,以为就是错了,然后把离散化去了,WA80?????!!!然后加上WA40。。。。然后我好好研究了一下,突然想到它可能询问从没出现过的颜色,然后判了一句,A了。。。。因为没出现过就是0,主席树查不出来。。。T3考场上吃屎一会再说。
T1:这是一道规律题,找的话其实打个父亲表,看一下就能知道,一个数的父亲就是这个数之前减去离他最近的斐波数,我们又可以知道这个斐波数增长飞快,见过通项的都知道,这玩意是指数级的,所以就可以打个表知道大概60多个就到13位了,找父亲log60,抬lca是60,一次操作就是常数,m次绝对可以接受,结果忘了之前搞得一个map没删,就死了30分。
#include<iostream> #include<cstdio> #include<algorithm> #include<map> using namespace std; long long f[10000]; long long rd() { long long s=0,w=1; char cc=getchar(); while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } long long fa(long long x) { long long id=lower_bound(f+1,f+64,x)-f-1; return x-f[id]; } long long getdep(long long tmp) { long long ans=0,x=tmp; while(x!=1) { ++ans; x=fa(x); } return ans; } long long lca(long long a,long long b) { int depa=getdep(a),depb=getdep(b); if(depa<depb) swap(a,b),swap(depa,depb); while(depa>depb) a=fa(a),depa--; if(a==b) return a; while(fa(a)!=fa(b)) a=fa(a),b=fa(b); return fa(a); } int main() { f[0]=1;f[1]=1; for(int i=2;i<=63;i++) { f[i]=f[i-1]+f[i-2]; } int m=rd(); for(int i=1;i<=m;i++) { long long a=rd(),b=rd(); if(a==1||b==1) { puts("1"); continue; } printf("%lld\n",lca(a,b)); } return 0; } /* g++ 1.cpp -o 1 ./1 5 1 1 2 3 5 7 7 13 4 12 */
T2:手动修改的主席树,因为这个修改不是修改,是交换,这很重要,那这样后面的主席树都不用改,只改一颗就行了,然后就可以性感询问,在线回复了。还是一样,可持久化烧内存,内存开够就没了。主席树码量极小
#include<iostream> #include<cstdio> using namespace std; const int N=300050; int rt[N],a[N],p[N],tt=0,cnt=0; struct tree{int lc,rc,w;}tr[50000020]; int rd() { int s=0,w=1; char cc=getchar(); while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } void insert(int &x,int l,int r,int p,int va) { tr[++tt]=tr[x];x=tt; if(l==r) { tr[x].w+=va; return; } int mid=(l+r)>>1; if(p<=mid) insert(tr[x].lc,l,mid,p,va); else insert(tr[x].rc,mid+1,r,p,va); } int query(int x,int l,int r,int p) { if(l==r)return tr[x].w; int mid=(l+r)>>1; if(p<=mid)return query(tr[x].lc,l,mid,p); else return query(tr[x].rc,mid+1,r,p); } int main() { int n=rd(),m=rd(); for(int i=1;i<=n;i++) { a[i]=rd(); if(!p[a[i]]) p[a[i]]=++cnt; } for(int i=1;i<=n;i++) { rt[i]=rt[i-1]; insert(rt[i],1,cnt,p[a[i]],1); } while(m--) { int op=rd(); if(op==1) { int l=rd(),r=rd(),c=rd(); if(!p[c]) puts("0"); else printf("%d\n",query(rt[r],1,cnt,p[c])-query(rt[l-1],1,cnt,p[c])); } else { int l=rd(); insert(rt[l],1,cnt,p[a[l]],-1); insert(rt[l],1,cnt,p[a[l+1]],1); swap(a[l],a[l+1]); } } } /* g++ 2.cpp -o 2 ./2 10 9 1 2 3 4 5 6 1 2 3 4 1 1 3 3 1 4 6 3 2 3 1 1 3 3 1 4 6 3 1 1 10 4 1 1 10 3 1 1 10 2 1 1 10 1 */
T3:首先这个题不是DP,倒着扫一遍,贪心找最长的合法区间,然后既能保证最少,也能保证最小。然后k=1的时候好搞,随便搞搞就行了,k=2的时候用二分图来做,我考试的时候鬼畜没看到k只能等于1或2,然后就开始yy,发现如果在一张图上如果把非敌对关系建图(反图)的话,在只有双联通分量里的点才能分成一个小组,于是我就开始了愉快的tarjan。。。。这题k=2的时候二分图可以跑过,我们就可以通过二分图判定,来判断这一堆猫啊不兔子是否能分两组,这个题的打法没怎么见过,不是dp只能瞎打。自己yy了一个调了一下午。
另外:亲测告诉各位卡常大师,sqrt函数我估计是$O(2^{n})$的,慢到没分数,直接打表比sqrt快3000ms
#include<iostream> #include<cmath> #include<cstdio> #include<cstring> //const int L=1<<20|1; //char buffer[L],*S,*T; //#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) using namespace std; const int N=3000050; bool v[N],ch[N]; int c[N],s[N],a[N],tt,qn,tot,fr[N*2]; struct node{int fr,to,pr;}mo[N*2]; void add(int x,int y) { mo[++tt].fr=x; mo[tt].to=y; mo[tt].pr=fr[x]; fr[x]=tt; } bool dfs(const register int x,const register int cl) { c[x]=cl; //cout<<x<<endl; for(int i=fr[x];i;i=mo[i].pr) { const register int to=mo[i].to; //cout<<to<<" "<<cl<<endl; if(c[to]==cl)return false; if(c[to]==0&&!dfs(to,-cl))return false; } return true; } int rd() { int s=0,w=1; char cc=getchar(); while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } int main() { int bm=0; int n=rd(),K=rd(); for(int i=1;i<=512;i++) ch[i*i]=1; for(int i=1;i<=n;i++) a[i]=rd(),bm=max(bm,a[i]); if(K==1) { for(int i=n;i;) { bool flag=1; int j=i; for(;j;j--) { for(int k=1;k<=512;k++) { if(v[k*k-a[j]]){flag=0;break;} } if(flag==0) break; v[a[j]]=1; } for(int k=j;k<=i;k++) v[a[k]]=0; i=j; if(j!=0) s[++tot]=j; } printf("%d\n",tot+1); for(int i=tot;i;i--) printf("%d ",s[i]); puts(""); return 0; } else { for(int i=n;i;) { bool flag=1; register int j=i; for(;j;j--) { for(int k=j+1;k<=i;k++)if(ch[a[j]+a[k]])add(j,k),add(k,j); for(int k=j;k<=i;k++)c[k]=0; if(!dfs(j,1))break; } for(int k=j;k<=i;k++)fr[k]=0; i=j;tt=0; s[++tot]=j; } printf("%d\n",tot); for(int i=tot-1;i;i--) printf("%d ",s[i]); puts(""); return 0; } } /* g++ 3.cpp -o 3 ./3 5 2 1 3 15 10 6 */