zoukankan      html  css  js  c++  java
  • [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
    ",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:

    [egin{equation} egin{array}{cccc} 16k&16k+1&16k+2&16k+3\ 16k+4&16k+5&16k+6&16k+7\ 16k+8&16k+9&16k+10&16k+11\ 16k+12&16k+13&16k+14&16k+15 end{array} end{equation} ]

    由于(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

  • 相关阅读:
    [UE4]RPC,远程调用
    [UE4]先报告后广播模式
    [UE4]复制引起的重复对象
    [UE4]封装蓝图函数Print String
    [UE4]碰撞的随机性
    [UE4]Authority,网络控制权
    [UE4]Replications,复制
    [UE4]最简单的虚幻4网络游戏,使用虚幻4内置服务器
    [UE4]Format Text
    [UE4]虚幻4链接独立服务器
  • 原文地址:https://www.cnblogs.com/xryjr233/p/CF1208.html
Copyright © 2011-2022 走看看