noip模拟9
宜:重构代码
T1
70分做法就是把1e6以内的直接父亲都暴力处理出来,询问时在线递归处理即可。
100分做法,发现每一层的最后一个数都是斐波那契数的一个值,并且一个数的父亲是这个数减去它的上一层的斐波那契数。求两个数祖先时一直递归往上跳,直到跳到二者相同时返回。
Code
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
namespace EMT{
typedef long long ll;
inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
ll f[65]={0,1,2};int m;
ll max(ll a,ll b){return a>b?a:b;}
int getdp(ll x){
int l=1,r=60,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(f[mid]<x)l=mid+1,ans=mid;
else r=mid-1;
}return ans;
}
inline ll getfa(ll x,ll y,int dep){
if(x==y)return x;
else if(x>y)return getfa(x-f[dep],y,getdp(max(x-f[dep],y)));
else return getfa(x,y-f[dep],getdp(max(x,y-f[dep])));
}
inline short main(){
F(i,3,60)f[i]=f[i-1]+f[i-2];
m=read();
F(i,1,m){
ll x=read(),y=read(),z=getdp(max(x,y));
pi(getfa(x,y,z));pn();
}
return 0;
}
}
int main(){return EMT::main();}
T2
有一个点卡了我好久啊。。。
不过我是不会放弃骗分分块的!
加了个小优化,结果一直T的点反而变成最快的点了...
Code
#include<bits/stdc++.h>
namespace EMT{
inline int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x;}
inline void write(int x){
static int sta[35];int top=0;
do{sta[++top]=x-(x/10)*10,x/=10;}while(x);
while(top) putchar(sta[top--]+'0');
putchar('\n');
}
inline void swap(int &a,int &b){int x=a;a=b,b=x;}
const int N=3e5+10;
short sum[400][N];
int size,n,m,a[N],pos[N],L,R,sp,x,c,ans;
inline short main(){
n=read();m=read();
size=pow(n,5.0/8.0);
for(int i=1;i<=n;i++)a[i]=read(),pos[i]=(i-1)/size+1,++sum[pos[i]][a[i]];
while(m--){
sp=read();
if(sp==1){
L=read(),R=read(),c=read(),ans=0;
if(pos[L]==pos[R]){
if(R-L+1<=size/2)for(int i=L;i<=R;i++)ans+=(a[i]==c);
else{
ans=sum[pos[L]][c];
for(int i=size*(pos[L]-1)+1;i<=L-1;i++)ans-=(a[i]==c);
for(int i=R+1;i<=size*pos[L];i++)ans-=(a[i]==c);
}
write(ans);
}else{
if(pos[L]*size-L+1<=size/2)for(int i=L;i<=pos[L]*size;i++)ans+=(a[i]==c);
else{
ans=sum[pos[L]][c];
for(int i=size*(pos[L]-1)+1;i<=L-1;i++)ans-=(a[i]==c);
}
for(int i=pos[L]+1;i<=pos[R]-1;i++)ans+=sum[i][c];
if(R-(pos[R]-1)*size<=size)for(int i=size*(pos[R]-1)+1;i<=R;i++)ans+=(a[i]==c);
else{
ans+=sum[pos[R]][c];
for(int i=R+1;i<=size*pos[R];i++)ans-=(a[i]==c);
}
write(ans);
}
}else{
x=read();
if(pos[x]==pos[x+1])swap(a[x],a[x+1]);
else{
--sum[pos[x]][a[x]];++sum[pos[x]][a[x+1]];
--sum[pos[x+1]][a[x+1]];++sum[pos[x+1]][a[x]];
swap(a[x],a[x+1]);
}
}
}
return 0;
}
}
int main(){return EMT::main();}
T3
不知道为什么一直92...重构代码后才过掉了。
倒序枚举是考场上想到了,不过1-512没想到,只想到了\(O(n^2)\)
40分:
枚举查看是否有冲突的即可。
100分:
使用并查集,特判一个数的二倍是不是完全平方数。
Code
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
int n,k;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
namespace EMT{
bool v[300000];int a[300000],ans[300000],cnt;
inline bool is(int x){int y=sqrt(x);return y*y==x;}
inline bool check(int x,int l,int r){
if(r-l+1>=512){F(i,1,512)if(v[i*i-x])return 0;}
else F(i,l,r)if(is(a[i]+x))return 0;
return 1;
}
inline void clean(int l,int r){
F(i,l,r)v[a[i]]=0;
}
inline short main(){
D(i,n,1)a[i]=read();
int key=1;v[a[1]]=1;
F(i,2,n)if(!check(a[i],key,i-1))clean(key,i-1),key=i,v[a[i]]=1,ans[++cnt]=n-i+1;else v[a[i]]=1;
pi(cnt+1);pn();D(i,cnt,1)pi(ans[i]);
return 0;
}
}
namespace emt{
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
const int N=1.5e5;
int a[500000],ans[500000],fa[500000],maxn,vis[500000],co,cnt;
inline int find(int x){return (x==fa[x])?x:fa[x]=find(fa[x]);}
inline bool is(int x){int y=sqrt(x);return y*y==x;}
inline void clean(int l,int r){F(o,l,r)vis[a[o]]=0,fa[a[o]]=a[o],fa[a[o]+N]=a[o]+N;}
inline short main(){
int key=n;bool fl;
F(i,1,n)a[i]=read(),maxn=max(maxn,a[i]);
F(i,1,maxn)fa[i]=i,fa[i+N]=i+N;
D(i,n,1){
fl=0;
if(vis[a[i]]){
if(is(a[i]*2)){
F(j,1,512){
if(vis[a[i]]==2||fa[a[i]+N]!=a[i]+N){
fl=1;break;
}
if(j*j<a[i])continue;
if(j*j>a[i]+maxn)break;
if(vis[j*j-a[i]]&&j*j!=a[i]*2){
fl=1;break;
}
}
if(fl){
ans[++cnt]=i;
F(j,i,key){
fa[a[j]]=a[j];fa[a[j]+N]=a[j]+N;
vis[a[j]]=0;
}
key=i;
}
}
}else{
F(j,1,512){
if(j*j<a[i])continue;
if(j*j>a[i]+maxn)break;
if(vis[j*j-a[i]]){
if(vis[j*j-a[i]]==2&&is((j*j-a[i])*2)){
fl=1;
break;
}
int x1=find(a[i]),x2=find(a[i]+N),y1=find(j*j-a[i]),y2=find(j*j-a[i]+N);
if(x1==y1){
fl=1;
break;
}
fa[y2]=x1;
fa[x2]=y1;
}
}
if(fl){
ans[++cnt]=i;
F(j,i,key){
fa[a[j]]=a[j];fa[a[j]+N]=a[j]+N;
vis[a[j]]=0;
}
key=i;
}
}
vis[a[i]]++;
}
pi(cnt+1);pn();
D(i,cnt,1)pi(ans[i]);
return 0;
}
}
int main(){
n=read();k=read();
if(k==1)return EMT::main();else return emt::main();}
Everything that kills me makes me feel alive.