8.3题解
T1[洛谷P3938]
题目很明显了,菲波那契,找规律无疑了,考场上的话,如果你对菲波那契足够敏感,那我想你是可以想到正解的,毕竟考场14个人AC,还算挺水的,如果实在想不出来,可以暴力打表找一下父亲,毕竟你是要不停的翻父亲,不管用什么方法吧,最后会发现$fa[x]=x-fib(x的出生月份-1)$,那我们再考虑一下对于$le12$的数据,他不停的翻父亲最多会翻多少遍,你会发现也就60遍,这个时候这道题就可做了,甚至不需要倍增,完全可以直接翻,但是由于你不知道深度,所以需要先把两个点分别翻一遍,找到深度,然后用类似于倍增$lca$的方法直接翻就可以了
1 #include<iostream> 2 #include<cstdio> 3 #include<set> 4 #define maxf 62 5 #define re register 6 #define ll long long 7 using namespace std; 8 const int L=1<<20|1; 9 char buffer[L],*S,*T; 10 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) 11 ll m; 12 ll f[maxf]; 13 set <ll> ccc; 14 inline ll read() 15 { 16 re ll aa=0,bb=1;re char cc=getchar(); 17 while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();} 18 while(cc<='9'&&cc>='0'){aa=aa*10+cc-'0';cc=getchar();} 19 return aa*bb; 20 } 21 inline int ef(re ll x) 22 { 23 re int l=1,r=61; 24 while(l<r) 25 { 26 if(l+1==r) 27 { 28 if(x>f[l]) return r; 29 else return l; 30 } 31 re int mid=(l+r)>>1; 32 if(x>f[mid]) l=mid+1; 33 else r=mid; 34 } 35 return l; 36 } 37 int main() 38 { 39 m=read(); 40 f[0]=1; f[1]=1; 41 for(re int i=2;i<maxf;++i) f[i]=f[i-1]+f[i-2]; 42 for(re int i=1;i<=m;++i) 43 { 44 ll a=read(),b=read(); ll ls1=a,ls2=b; 45 int deepa=0,deepb=0; 46 while(ls1>1) {deepa++; ls1-=f[ef(ls1)-1];} 47 while(ls2>1) {deepb++; ls2-=f[ef(ls2)-1];} 48 if(deepa<deepb) {swap(deepa,deepb); swap(a,b);} 49 while(deepa>deepb) {a-=f[ef(a)-1]; deepa--;} 50 while(a!=b) {a-=f[ef(a)-1]; b-=f[ef(b)-1];} 51 printf("%lld\n",a); 52 } 53 return 0; 54 }
T2[洛谷P3939]
这题和BZOJ2120相似度不是一般的高啊,$BZOJ2120$可是个带修莫队的板子题,不过很可惜,我并没有学,后来颓了题解之后,给我一种这题很简单的感觉,只要$STL$可以6到飞起,这题就没问题,这题二元组排序,颜色做第一维,位置做第二维,先来考虑一下修改操作吧,你会发现他是交换$x$和$x+1$的位置,那对于你排好的序列是没有影响的,只要改掉位置就可以了,所以只需要lower_bound找到要修改的点,把第二维改一下就可以了,不过由于lower_ bound的特殊性,平常结构题进行二元组排序的思路被舍弃了,这时候有出现了一个新的$STL$:$pair$,其实就是个结构体,只不过已经定义好了,且只有两维,具体的实现方法可以参照下面的代码,修改搞定了,然后就是询问了,既然是按照颜色排序,那就只需要一个upper_bound和一个lower_bound,分别用来查找第一个大于$r$的位置和第一个大于等于$l$的位置,做差即可
话说这题打$treap$,主席树,树套树等等,各种数据结构,大力卡常都可以拿到一个不错的成绩,$treap$都可以直接A
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define maxn 300100 5 using namespace std; 6 pair <int,int> a[maxn]; 7 int n,m; 8 int Cc[maxn]; 9 inline int read(){ 10 register int ret; 11 register char r; 12 while(r=getchar(),r<'0'||r>'9');ret=r-48; 13 while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48; 14 return ret; 15 } 16 int main() 17 { 18 n=read(); m=read(); 19 for(int i=1;i<=n;++i) {a[i].first=read(); Cc[i]=a[i].first; a[i].second=i;} 20 sort(a+1,a+n+1); 21 for(int i=1;i<=m;++i) 22 { 23 int opt=read(); 24 if(opt==1) 25 { 26 int l=read(),r=read(),Col=read(); 27 pair <int,int> ls; 28 ls.first=Col; ls.second=l; 29 int wz1=lower_bound(a+1,a+n+1,ls)-a; 30 pair <int,int> lss; 31 lss.first=Col; lss.second=r; 32 int wz2=upper_bound(a+1,a+n+1,lss)-a; 33 int ans=wz2-wz1; 34 printf("%d\n",ans); 35 } 36 else 37 { 38 int x=read(); 39 if(Cc[x]==Cc[x+1]) continue; 40 else 41 { 42 int ls=Cc[x]; 43 pair <int,int> ls1; 44 ls1.first=Cc[x]; ls1.second=x; 45 int wz1=lower_bound(a+1,a+n+1,ls1)-a; 46 a[wz1].second=x+1; Cc[x]=Cc[x+1]; 47 pair <int,int> ls2; 48 ls2.first=Cc[x+1]; ls2.second=x+1; 49 int wz2=lower_bound(a+1,a+n+1,ls2)-a; 50 a[wz2].second=x; Cc[x+1]=ls; 51 } 52 } 53 } 54 return 0; 55 }
T3[洛谷P3940]
这题$k==1||k==2$一看就友好啊,先骗8分没问题
说实话$k==1$就是个暴力,因为每个块内都不能冲突,所以暴力扫一遍,碰到冲突的直接分组就可以了,字典序最小的话就是前面多分组,后面少分组呗,那从后向前扫,直接贪心就可做,不过如果暴力扫当前块中的数,判是否冲突的话,很大的可能性会T,我们会发现他有一个有趣的性质,最大的数为什么是131072呢,一般不都应该是$le$几之类的数嘛,好巧不巧,两个131072加和,恰好是$512^2$,那我们枚举512,肯定比枚举当前块所有的数划算啊,所以,直接枚举到512,列出所有的平方数,和当前准备加入的点做差,看看这个差是否存在在当前组内就可以了
对于$k==2$,和关押罪犯有些像,而这两道题,用并查集或交叉染色判二分图都可做,我用的二分图,每加入一个点,就对当前组内所有的点跑一遍二分图,如果不能构成二分图,直接分组即可,并查集的思想和这个类似,依旧是从后往前扫贪心
$tips$:清空的时候不要$memset$,放进去几个点清空几个点,不然一不注意就会T,不过一定要清空啊!!还有就是重复的点,建图的时候别忘了
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<vector> 5 #include<cstring> 6 #define maxn 270000 7 using namespace std; 8 /*const int L=1<<20|1; 9 char buffer[L],*S,*T; 10 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)*/ 11 int n,k,js=1; 12 int a[maxn],ans[maxn],pd[maxn]; 13 vector <int> b[maxn],bb[maxn],c[maxn]; 14 int jss,bjjj; 15 int head[maxn],to[maxn*2],xia[maxn*2],visit[maxn]; 16 inline int read() 17 { 18 int ret; 19 char r; 20 while(r=getchar(),r<'0'||r>'9');ret=r-48; 21 while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48; 22 return ret; 23 } 24 void add(int x,int y) 25 { 26 to[++jss]=y; xia[jss]=head[x]; head[x]=jss; 27 } 28 void dfs(int x,int colo) 29 { 30 visit[x]=colo; 31 for(int i=head[x];i;i=xia[i]) 32 { 33 int ls=to[i]; 34 if(ls<=bb[js][0]) 35 { 36 if(visit[ls]==0) dfs(ls,3-colo); 37 else if(visit[ls]==colo) {bjjj=1; return ;} 38 } 39 } 40 } 41 int main() 42 { 43 // freopen("division18.in","r",stdin); 44 n=read(); k=read(); 45 for(int i=1;i<=n;++i) a[i]=read(); 46 if(k==1) 47 { 48 int zz=n; 49 while(zz>0) 50 { 51 if(b[js].size()!=0) 52 for(int i=2;i<=512;++i) 53 { 54 int ls1=i*i-a[zz]; 55 if(pd[ls1]==1) 56 { 57 for(int i=0;i<b[js].size();++i) pd[b[js][i]]=0; 58 ans[++js]=zz; break; 59 } 60 } 61 b[js].push_back(a[zz]); pd[a[zz]]=1; zz--; 62 } 63 printf("%d\n",js); 64 for(int i=js;i>=2;--i) printf("%d ",ans[i]); 65 puts(""); 66 } 67 else 68 { 69 for(int i=n;i>=1;--i) 70 { 71 if(b[js].size()==0) 72 { 73 b[js].push_back(a[i]); bb[js].push_back(i); 74 pd[a[i]]=1; c[a[i]].push_back(i); 75 continue; 76 } 77 for(int j=2;j<=512;++j) 78 { 79 int ls1=j*j-a[i]; bjjj=0; 80 if(pd[ls1]!=0) 81 { 82 for(int k=0;k<c[ls1].size();++k) 83 if(js==1||c[ls1][k]<=bb[js][0]) 84 {add(c[ls1][k],i); add(i,c[ls1][k]);} 85 for(int k=0;k<bb[js].size();++k) visit[bb[js][k]]=0; 86 for(int k=0;k<bb[js].size();++k) 87 if(visit[bb[js][k]]==0) dfs(bb[js][k],1); 88 for(int k=0;k<bb[js].size();++k) visit[bb[js][k]]=0; 89 visit[i]=0; 90 } 91 if(bjjj==1) 92 { 93 for(int k=1;k<=jss;++k) {to[k]=0; xia[k]=0;} 94 for(int k=0;k<b[js].size();++k) 95 {head[bb[js][k]]=0; pd[b[js][k]]=0;} 96 head[i]=0; jss=0; js++; 97 } 98 } 99 b[js].push_back(a[i]); bb[js].push_back(i); 100 c[a[i]].push_back(i); pd[a[i]]=1; 101 } 102 printf("%d\n",js); 103 for(int i=js;i>=2;--i) printf("%d ",bb[i][0]); 104 puts(""); 105 } 106 return 0; 107 }