[2019.8.25]codeforces1208 Manthan, Codefest 19 (open for everyone, rated, Div. 1 + Div. 2)
概况
排名: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\n",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\)和\(0\le 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]," \n"[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