考场错误:
注意二分的边界问题,写
l
=
m
i
d
+
1
,
r
=
m
i
d
−
1
l=mid+1,r=mid-1
l=mid+1,r=mid−1的话是
w
h
i
l
e
(
l
≤
r
)
while(l\le r)
while(l≤r)
注意一些corner case,多想一想
补题
gym103687F Easy Fix
首先,使用树状数组求出初始每个位置的a,b,c的值
接着考虑一次交换操作可能带来的影响,一定是来自 [ l + 1 , r − 1 ] [l+1,r-1] [l+1,r−1]内部的
首先我们考虑 p [ l ] < p [ r ] p[l] < p[r] p[l]<p[r]的情况
对于内部的一个位置 j j j,如果原本 p [ l ] < p [ j ] < p [ r ] p[l]<p[j]<p[r] p[l]<p[j]<p[r],那么修改后会使得 a [ j ] − 1 , b [ j ] + 1 a[j]-1,b[j]+1 a[j]−1,b[j]+1,因此当原来 a [ j ] ≤ b [ j ] a[j]\le b[j] a[j]≤b[j]的时候,对答案的贡献会减少1
对于内部的一个位置 j j j,如果原本 p [ l ] < p [ j ] < p [ r ] p[l]<p[j]<p[r] p[l]<p[j]<p[r],那么修改后会使得 a [ j ] − 1 , b [ j ] + 1 a[j]-1,b[j]+1 a[j]−1,b[j]+1,因此当原来 b [ j ] + 1 ≤ a [ j ] − 1 b[j]+1\le a[j]-1 b[j]+1≤a[j]−1的时候,对答案的贡献会增加1
同理当 p [ l ] > p [ r ] p[l] > p[r] p[l]>p[r]
对于内部的一个位置 j j j,如果原本 p [ r ] < p [ j ] < p [ l ] p[r]<p[j]<p[l] p[r]<p[j]<p[l],那么修改后会使得 a [ j ] + 1 , b [ j ] − 1 a[j]+1,b[j]-1 a[j]+1,b[j]−1,因此当原来 b [ j ] ≤ a [ j ] b[j]\le a[j] b[j]≤a[j]的时候,对答案的贡献会减少1
对于内部的一个位置 j j j,如果原本 p [ l ] < p [ j ] < p [ r ] p[l]<p[j]<p[r] p[l]<p[j]<p[r],那么修改后会使得 a [ j ] + 1 , b [ j ] − 1 a[j]+1,b[j]-1 a[j]+1,b[j]−1,因此当原来 a [ j ] + 1 ≤ b [ j ] − 1 a[j]+1\le b[j]-1 a[j]+1≤b[j]−1的时候,对答案的贡献会增加1
所以开五个主席树即可解决了,每次相当于查询区间内的满足 p [ r ] < p [ j ] < p [ l ] p[r]<p[j]<p[l] p[r]<p[j]<p[l]的个数,第五个主席树用于记录l和r位置的贡献
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;
int a[maxn],b[maxn],c[maxn],sum[maxn];
int tr[maxn],p[maxn];
int lowbit(int x)
{
return x&-x;
}
void add(int x,int v)
{
while(x<=n)
{
tr[x]+=v;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x)
{
res+=tr[x];
x-=lowbit(x);
}
return res;
}
struct chairman
{
int rt[maxn],tot;
int ls[maxn<<5],rs[maxn<<5],val[maxn<<5];
void cpy(int u,int v)
{
ls[u]=ls[v]; rs[u]=rs[v]; val[u]=val[v];
}
void modify(int &u,int v,int l,int r,int pos,int gs)
{
u=++tot; cpy(u,v);
val[u]+=gs;
if(l==r) return;
int mid=l+r>>1;
if(pos<=mid) modify(ls[u],ls[v],l,mid,pos,gs);
else modify(rs[u],rs[v],mid+1,r,pos,gs);
}
int query(int s,int t,int l,int r,int L,int R)
{
// cerr<<s<<" "<<t<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
if(l>=L && r<=R)
return val[t]-val[s];
int mid=l+r>>1;
if(R<=mid) return query(ls[s],ls[t],l,mid,L,R);
if(mid<L) return query(rs[s],rs[t],mid+1,r,L,R);
return query(ls[s],ls[t],l,mid,L,R)+query(rs[s],rs[t],mid+1,r,L,R);
}
}A,B,C,D,E;
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++)
{
a[i]=query(p[i]);
b[i]=p[i]-a[i]-1;
c[i]=min(a[i],b[i]);
sum[i]=sum[i-1]+c[i];
add(p[i],1);
}
// cerr<<sum[n];
// return 0;
for(int i=1;i<=n;i++)
{
if(a[i]<=b[i]) A.modify(A.rt[i],A.rt[i-1],1,n,p[i],-1);
else A.rt[i]=A.rt[i-1];
if(a[i]-1>=b[i]+1) B.modify(B.rt[i],B.rt[i-1],1,n,p[i],1);
else B.rt[i]=B.rt[i-1];
if(a[i]>=b[i]) C.modify(C.rt[i],C.rt[i-1],1,n,p[i],-1);
else C.rt[i]=C.rt[i-1];
if(b[i]-1>=a[i]+1) D.modify(D.rt[i],D.rt[i-1],1,n,p[i],1);
else D.rt[i]=D.rt[i-1];
E.modify(E.rt[i],E.rt[i-1],1,n,p[i],1);
}
// return 0;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int l,r;
// cerr<<i;
scanf("%d%d",&l,&r);
if(l==r)
{
printf("%d\n",sum[n]);
continue;
}
if(l>r) swap(l,r);
int ans=sum[n]-c[l]-c[r],tmp;
if(p[l]<p[r])
{
ans+=A.query(A.rt[l],A.rt[r-1],1,n,p[l],p[r]);
// return 0;
ans+=B.query(B.rt[l],B.rt[r-1],1,n,p[l],p[r]);
// return 0;
tmp=E.query(E.rt[0],E.rt[l-1],1,n,1,p[r]);
ans+=min(tmp,p[r]-1-tmp);
tmp=E.query(E.rt[r],E.rt[n],1,n,1,p[l]);
ans+=min(tmp,p[l]-1-tmp);
// cerr<<ans;
// return 0;
}
else
{
ans+=C.query(C.rt[l],C.rt[r-1],1,n,p[r],p[l]);
ans+=D.query(D.rt[l],D.rt[r-1],1,n,p[r],p[l]);
tmp=E.query(E.rt[0],E.rt[l-1],1,n,1,p[r]);
ans+=min(tmp,p[r]-1-tmp);
tmp=E.query(E.rt[r],E.rt[n],1,n,1,p[l]);
ans+=min(tmp,p[l]-1-tmp);
}
printf("%d\n",ans);
}
return 0;
}
Gym - 103687I
首先,如果这个子串是回文的,先手就输了,这个可以通过哈希来判断
接着,考虑所有先手必输的情况,即取两段后的结果都是回文串,可以通过观察发现,这类串的长度为偶数
综合以上两个情况,可以完成代码,复习了字符串哈希,可以尝试使用马拉车实现回文串的判断!
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn=1e6+5;
const ull base=233333;
int n,q;
ull has[maxn],Has[maxn],pw[maxn];
char s[maxn];
bool is_pr(int l,int r)
{
if(has[r]-has[l-1]*pw[r-l+1]==Has[l]-Has[r+1]*pw[r-l+1])
return true;
return false;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d%d",&n,&q);
scanf("%s",s+1);
pw[0]=1;
for(int i=1;i<=n;i++)
{
pw[i]=pw[i-1]*base;
has[i]=has[i-1]*base+s[i];
}
for(int i=n;i>=1;i--) Has[i]=Has[i+1]*base+s[i];
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
if(is_pr(l,r) || (r-l)&1) printf("Budada\n");
else printf("Putata\n");
}
return 0;
}
Gym - 103687J
计算几何好久不写,十分生疏,这算是一个复习的开始吧,注意顺时针和逆时针的方向向量的不同,一些细节一定要注意!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI=acos(-1);
int T;
int st,ed;
struct node
{
double x,y;
node operator + (node &oth) const
{
return (node){x+oth.x,y+oth.y};
}
node operator - (node &oth) const
{
return (node){x-oth.x,y-oth.y};
}
}s,t;
int cnt;
node get(int ang)
{
node res;
res.x=cos(PI*ang/180);
res.y=sin(PI*ang/180);
return res;
}
double sqr(double x)
{
return x*x;
}
double dist(node x,node y)
{
return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
}
void print(node x)
{
printf("%.10lf %.10lf\n",x.x,x.y);
}
node rot_90(node x)
{
return (node){-x.y,x.x};
}
double cross(node a,node b)
{
return a.x*b.y-a.y*b.x;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&T);
while(T--)
{
int rev=0;
scanf("%d%d",&st,&ed);
s=get(st); t=get(ed);
int dis=min((st-ed+360)%360,(ed-st+360)%360);
if(!dis)
{
printf("0\n");
print(s);
continue;
}
if(dis<=90)
{
node dir=s-t; dir=rot_90(dir);
double d=dist(s,t);
// cerr<<t.x<<" "<<sin(PI/2);
dir.x/=d; dir.y/=d;
// printf("!");
if(cross(s,t)<0) dir.x*=-1,dir.y*=-1;
// print(dir);
double l=sqrt(1-d*d/4);
// cerr<<l;
node M; M.x=(s.x+t.x)/2; M.y=(s.y+t.y)/2;
dir.x*=l,dir.y*=l;
node tmp=M+dir;
printf("%d\n",2);
// cerr<<t.x<<" "<<t.y;
print(s); print(tmp); print(t);
continue;
}
if(dis<=131)
{
node dir=s-t,Dir=s-t; dir=rot_90(dir);
double d=dist(s,t);
dir.x/=d; dir.y/=d; Dir.x/=d*2; Dir.y/=d*2;
if(cross(s,t)<0) dir.x*=-1,dir.y*=-1;
node tmp1,tmp2;
double l=sqrt(1-sqr(d/2-0.5));
dir.x*=l,dir.y*=l;
node M; M.x=(s.x+t.x)/2; M.y=(s.y+t.y)/2;
tmp1=M+dir+Dir; tmp2=M+dir-Dir;
printf("3\n");
print(s); print(tmp1); print(tmp2); print(t);
continue;
}
node Dir=rot_90(s);
if(cross(s,t)<0) Dir.x*=-1,Dir.y*=-1;
node tmp1=s+Dir,tmp2=tmp1-s;
printf("4\n");
print(s); print(tmp1); print(tmp2);
s=tmp2;
node dir=s-t; dir=rot_90(dir);
double d=dist(s,t);
dir.x/=d; dir.y/=d;
if(cross(s,t)<0) dir.x*=-1,dir.y*=-1;
double l=sqrt(1-d*d/4);
node M; M.x=(s.x+t.x)/2; M.y=(s.y+t.y)/2;
dir.x*=l,dir.y*=l;
node tmp=M+dir;
print(tmp); print(t);
}
return 0;
}