概况
排名:304/6994
过题数:5
Rating:(color{green}{+44})((color{orange}{2147}))
题目
A. XORinacci
AC时间:5min,490分
题解:
首先按二进制位考虑。
对于每一位,如果(F(0),F(1))为0,那么这一位必然是0;
其余三种都是四位循环的。直接判断即可。
code:
#include<bits/stdc++.h>
using namespace std;
int T,a,b,n,ans;
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&a,&b,&n),ans=0;
for(int i=1;i<=a||i<=b;i<<=1){
if((a&i)&&(b&i))ans|=i*(n%3!=2);
else if(a&i)ans|=i*(n%3!=1);
else if(b&i)ans|=i*(n%3!=0);
}
printf("%d
",ans);
}
return 0;
}
B.Uniqueness
AC时间:14min,944分
题解:
离散化,然后枚举起点,枚举终点。对于同一起点,终点可以直接转移。
code:
#include<bits/stdc++.h>
using namespace std;
struct ST{
int v,id;
}s[2010];
int n,a[2010],tmp,num[2010],t[2010],ans=1e9,tg=1,tt,mn;
bool cmp(ST x,ST y){
return x.v<y.v;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&s[i].v),s[i].id=i;
sort(s+1,s+n+1,cmp);
for(int i=1;i<=n;++i)tmp+=s[i].v!=s[i-1].v,a[s[i].id]=tmp,++num[tmp],tg&=(num[tmp]==1);
if(tg)return puts("0"),0;
for(int i=1;i<=n;++i){
for(int j=1;j<=tmp;++j)t[j]=num[j],tt+=t[j]>1;
for(mn=i;mn<=n&&tt;++mn)--t[a[mn]],tt-=t[a[mn]]==1;
if(!tt)ans=min(ans,mn-i);
}
printf("%d",ans);
return 0;
}
C.Magic Grid
AC时间:52min,1188分
(坑死我了)
题解:
两个重要性质:
对于任意非负整数(k),有((4k)xor(4k+1)xor(4k+2)xor(4k+3)=0)
另外,对于非负整数(k)和(0le p<4),有((16k+p)xor(16k+4+p)xor(16k+8+p)xor(16k+12+p)=0)
注意到(0 xor 1 xor 2 xor 3=0),上述两点都容易证明。
于是,对于任意一个(k),下面方阵的任意行列异或和为0:
由于(n)是4的倍数,直接这样构造即可。
code:
#include<bits/stdc++.h>
using namespace std;
int n,mp[1010][1010],tt;
void Work(int x,int y){
for(int i=0;i<4;++i)for(int j=0;j<4;++j)mp[x+i][y+j]=tt++;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i+=4)for(int j=1;j<=n;j+=4)Work(i,j);
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)printf("%d%c",mp[i][j],"
"[j==n]);
return 0;
}
D.Restore Permutation
AC时间:1h8min,1456分
(没错我D用了16min,C用了38min)
题解:
考虑从后往前计算。
记在算完一段后缀后,如果在下一个位置放置(x),那么所有满足条件的数的和为(sum_x)。
一开始,(sum_x=frac{x(x-1)}{2})
对于当前位置(i),我们可以二分求得满足(sum_x=s_i)的(x)。
然后,我们要更新(sum)。相当于对所有(k>x),令(sum_k=sum_k-x)。
线段树维护即可。
还有一个问题,有些数已经放过了,但是我们二分的时候还是会二分到它,也就是说满足(sum_x=s_i)的可能是一段(x),而不是一个(x)。
事实上,我们要找的(x)应该是所有满足(sum_x=s_i)的(x)中最大的。
code:
#include<bits/stdc++.h>
#define ci const int&
#define Upd(x) (t[x].sum=t[x<<1].sum+t[x<<1|1].sum)
#define Sum(x) (1ll*(x+1)*(x)/2ll)
using namespace std;
struct node{
int l,r;
long long sum;
}t[800010];
int n,prt[200010];
long long s[200010];
void Build(ci x,ci l,ci r){
t[x].l=l,t[x].r=r;
if(l==r)return;
int mid=l+r>>1;
Build(x<<1,l,mid),Build(x<<1|1,mid+1,r);
}
void Change(ci x,ci id){
if(t[x].l==t[x].r)return(void)(t[x].sum=id);
int mid=t[x].l+t[x].r>>1;
id<=mid?Change(x<<1,id):Change(x<<1|1,id),Upd(x);
}
long long Query(ci x,ci l,ci r){
if(l>r)return 0;
if(t[x].l==l&&t[x].r==r)return t[x].sum;
int mid=t[x].l+t[x].r>>1;
return r<=mid?Query(x<<1,l,r):(l>mid?Query(x<<1|1,l,r):(Query(x<<1,l,mid)+Query(x<<1|1,mid+1,r)));
}
int l,r,mid;
int main(){
scanf("%d",&n),Build(1,1,n);
for(int i=1;i<=n;++i)scanf("%I64d",&s[i]);
for(int i=n;i>=1;--i){
l=1,r=n;
while(l<r)mid=l+r+1>>1,Sum(mid-1)-Query(1,1,mid-1)<=s[i]?l=mid:r=mid-1;
prt[i]=l,Change(1,l);
}
for(int i=1;i<=n;++i)printf("%d ",prt[i]);
return 0;
}
E.Let Them Slide
AC时间:2h4min,1084分(-1)
题解:
对于每个长度为(l)的条(a),它能够对应位置(k)的数其实是(a)中的一段区间([max(1,k-(w-l)),min(l,k)])。
由于一些位置可以不对应任何数,我们令(a_0=a_{l+1}=0),上面那个区间改为([max(0,k-(w-l)),min(l+1,k)])。
然后从小到大枚举位置(i),每次至多增加一个位置或者减少一个位置,可以单调队列维护。
但是这样就(T)了。
因为事实上上面的算法是(O(nw))的,可以令(n=w=10^6),每一个条长度为1。
考虑对于很短的条(a),中间有许多位置都可以对应(a)中的所有数。
因此我们只要计算出可以对应所有数的区间,区间中的数直接通过差分的办法区间加上条上数的最大值。
而对于剩下部分,数量是(O(l))的。
因此时间复杂度变为(O(sum l))。
code:
讲起来简单,其实有不少细节。
(这就是你一份代码写将近1h的理由?)
#include<bits/stdc++.h>
#define ci const int&
using namespace std;
int n,w,len,t,mx,dq[1000010],id[1000010],hd,tl;
long long d[1000010];
vector<int>a[1000010];
void Add(ci x,ci ind){
if(ind>=a[x].size())return;
while(hd>=tl&&dq[hd]<=a[x][ind])--hd;
dq[++hd]=a[x][ind],id[hd]=ind;
}
void Del(ci x,ci ind){
if(id[tl]==ind)++tl;
}
int main(){
scanf("%d%d",&n,&w);
for(int i=1;i<=n;++i){
scanf("%d",&len),hd=0,tl=1,a[i].push_back(0),mx=0;
for(int j=1;j<=len;++j)scanf("%d",&t),a[i].push_back(t),mx=max(mx,t);
a[i].push_back(0),Add(i,0),Add(i,1);
if(w-len==0)Del(i,0);
for(int j=1;j<=len+1;Del(i,j-(w-len)),++j,Add(i,j))d[j]+=dq[tl],d[j+1]-=dq[tl];
if(len+1<w-len)d[len+2]+=mx,d[w-len+1]-=mx,Del(i,0);
for(int j=max(w-len+1,len+2);j<=w;++j)d[j]+=dq[tl],d[j+1]-=dq[tl],Del(i,j-(w-len));
}
for(int i=1;i<=w;++i)d[i]+=d[i-1],printf("%I64d ",d[i]);
return 0;
}
总结
比赛最后14s AC了E题
还好延时了5min...不然橙名估计就没了
C题是真的自闭,D和E看到题面2min内就想出了正解...QWQ