zoukankan      html  css  js  c++  java
  • ZROI-Day2比赛解题报告

    ZROIDay2-比赛解题报告

    版权原因不提供题面信息


    这几天作息有点鬼畜,虽然昨晚很晚睡但是早上精神还不错,看到题发现T1很友好?T2woc这暴力都好难打?T3多项式?!这样下去比赛会不会出现更多高端操作,恐怕凉凉

    A

    感谢出题人,暴力好打分又多,正解也不难想,这题基本上部分分都打了一遍

    50pts

    对于每一个炮将其所在的所在的交叉行(暂且这么说)(O(1)) 标记,然后(O(N^2))遍历一遍统计就好了

    70pts

    核心思想是计算出放一个炮新增的贡献,即它能覆盖的点数减去已经覆盖的点数,最后(N^2)减去总和既是答案

    拿这部分分还花了不少功夫,终于运用人类智慧找出一些规律,也就是对于一个炮((x,y)),它左斜行和右斜行能覆盖的点的个数,然后又发现对于一个确定的左斜行(即确定的(x+y)),可以通过(x,y)计算出与它有公共点的左斜行的(x-y)的相关信息,于是新增一个炮,在他所在的左斜行加上+1标记,加上左斜行覆盖点数,在枚举与左斜行有公共点的右斜行,假设这个右斜行已有标记,则贡献-1。对于右斜行也类似

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cctype>
    #include <queue>
    #include <cmath>
    #define ll long long 
    #define ri register int 
    #define ull unsigned loong long 
    const int maxn=100005;
    const int inf=0x7ffffffff;
    template <class T>inline void read(T &x){
    	x=0;int ne=0;char c;
    	while(!isdigit(c=getchar()))ne=c=='-';
    	x=c-48;
    	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    	x=ne?-x:x;return;
    }
    int n,m;
    int p[maxn<<1],q[maxn<<1];
    int cntp=0,cntq=0;
    inline void solve_2(){
    	int x,y;ll ans=0;
    	while(m--){
          read(x),read(y);
          if(!p[x+y]){
          	p[x+y]=1;
          	cntp++;
          	if(x+y<=n){
          	  int k=x+y-2;//
          	  ans+=x+y-1;//ok
          	  for(ri i=-k;i<=k;i+=2){
          	  	ans-=q[i+n];
    		  }
    		}
          	else{
          	  int k=n*2-(x+y);
          	  ans+=k+1;
          	  for(ri i=(x+y)-n*2;i<=n*2-(x+y);i+=2){
          	  	ans-=q[i+n];
    		  }
    		}
    	  }
    	  if(!q[x-y+n]){
    	  	q[x-y+n]=1;
    	  	cntq++;
    	  	if(x-y<=0){
    	  		int k=x-y+n-1;
    	  		ans+=n+(x-y);
    	  		for(ri i=n+1-k;i<=n+1+k;i+=2){
    	  			ans-=p[i];
    			}
    		}
    		else{
    			int k=x-y-n+1;
    			ans+=n-(x-y);
    			for(ri i=n+1+k;i<=n+1-k;i+=2){
    				ans-=p[i];
    			}
    		}
    	  }
    	}
    	printf("%lld
    ",1ll*n*n-ans);
    }
    int main(){ 
    	int x,y;
    	ll ans=0;
    	freopen("dat.in","r",stdin);
    	freopen("bf.out","w",stdout);
    	read(n),read(m);
        solve_2();
    	return 0;
    }
    

    100pts

    发现每个左斜行能确定的右斜行的x-y范围是连续的的奇数或偶数,于是用线段树维护标记和区间和,复杂度$O( m $ $log $ (N))

    然后鬼畜的是刚码完大样例过不了,以为是奇偶数搞错,魔改了半天后发现有一个判定没写到循环里。。。然后又魔改还是不对,于是开始对拍手动gdb调试,发现有一颗线段树操作的上限因为是x+y要设成(2n),查完这个错后据考试结束还有不到半小时,真TM刺激

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cctype>
    #include <ctime>
    #include <queue>
    #include <cmath>
    #define ll long long 
    #define ri register int 
    #define ull unsigned loong long 
    const int maxn=200015;
    const int inf=0x7fffffff;
    template <class T>inline void read(T &x){
    	x=0;int ne=0;char c;
    	while(!isdigit(c=getchar()))ne=c=='-';
    	x=c-48;
    	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    	x=ne?-x:x;return;
    }
    int n,m,N;
    bool p[maxn<<1],q[maxn<<1];
    int L,R,dta,t;
    struct Segment_Tree_1{
    	int ns[maxn<<2],odds[maxn<<2];//fff是没用的
    	void update(int now,int l,int r,int fff){//printf("%d****%d
    ",l,r);
    		if(l==r){
    			if(l&1)odds[now]++;
    			else ns[now]++;
    			return ;
    		}
    		int mid=(l+r)>>1;
    		if(t<=mid)update(now<<1,l,mid,fff);
    		else update(now<<1|1,mid+1,r,fff);
    		odds[now]=odds[now<<1]+odds[now<<1|1];
    		ns[now]=ns[now<<1]+ns[now<<1|1];
    		return ;
    	}
    	int odd_query(int now,int l,int r){
    		if(L<=l&&r<=R){
    			return odds[now];
    		}
    		int mid=(l+r)>>1,ans=0;
    		if(L<=mid)ans+=odd_query(now<<1,l,mid);
    		if(mid<R)ans+=odd_query(now<<1|1,mid+1,r);
    		return ans;
    	}
    	int n_query(int now,int l,int r){
    		if(L<=l&&r<=R){
    			return ns[now];
    		}
    		int mid=(l+r)>>1,ans=0;
    		if(L<=mid)ans+=n_query(now<<1,l,mid);
    		if(mid<R)ans+=n_query(now<<1|1,mid+1,r);
    		return ans;
    	}
    }P;
    struct Segment_Tree_2{
    	int ns[maxn<<1],odds[maxn<<1];
    	void update(int now,int l,int r,int fff){
    		if(l==r){			
    			if(l&1)odds[now]++;
    			else ns[now]++;
    			return ;
    		}
    		int mid=(l+r)>>1;
    		if(t<=mid)update(now<<1,l,mid,fff);
    		else update(now<<1|1,mid+1,r,fff);
    		odds[now]=odds[now<<1]+odds[now<<1|1];
    		ns[now]=ns[now<<1]+ns[now<<1|1];
    		return ;
    	}
    	int odd_query(int now,int l,int r){
    		if(L<=l&&r<=R){
    			return odds[now];
    		}
    		int mid=(l+r)>>1,ans=0;
    		if(L<=mid)ans+=odd_query(now<<1,l,mid);
    		if(mid<R)ans+=odd_query(now<<1|1,mid+1,r);
    		return ans;
    	}
    	int n_query(int now,int l,int r){
    		if(L<=l&&r<=R){
    			return ns[now];
    		}
    		int mid=(l+r)>>1,ans=0;
    		if(L<=mid)ans+=n_query(now<<1,l,mid);
    		if(mid<R)ans+=n_query(now<<1|1,mid+1,r);
    		return ans;
    	}
    }Q1,Q2;
    inline void solve(){
    	int x,y;ll ans=0;
    	while(m--){
          read(x),read(y);
          if(!p[x+y]){
          	t=x+y;
          	P.update(1,1,N,0);
    		p[x+y]=1;
          	if(x+y<=n){
          	  int k=x+y-2;
          	  ans+=x+y-1;
          	  int lxl=-k,rr=k;
          	  if(lxl==rr){
          	  	L=R=0;
    			if(q[n])ans--;
    		  }
          	  else {
          	    L=0,R=abs(lxl);
    			if(R&1)ans-=Q1.odd_query(1,0,n);
    			else ans-=Q1.n_query(1,0,n);
    		    L=1,R=rr;
    		    if(R&1)ans-=Q2.odd_query(1,1,n);
    		    else ans-=Q2.n_query(1,1,n);
    		  }
    		}
          	else{
          	  int k=n*2-(x+y);
          	  ans+=k+1;
          	  int lxl=(x+y)-n*2,rr=n*2-(x+y);
          	  //printf("2--%d ",ans);
          	  if(lxl==rr){
          	  	L=R=0;
    			if(q[n])ans--;//ans-=Q1.n_query(1,0,n);
    		  }
          	  else {
          	    L=0,R=abs(lxl);
    			if(R&1)ans-=Q1.odd_query(1,0,n);
    			else ans-=Q1.n_query(1,0,n);
    		    L=1,R=rr;
    		    if(R&1)ans-=Q2.odd_query(1,1,n);
    		    else ans-=Q2.n_query(1,1,n);
    		  }
    		}		
    	  }
    	  if(!q[x-y+n]){
    	  	t=x-y;
    	  	if(t<=0){
    	  		t=abs(t);
    		    Q1.update(1,0,n,1);
    		}
    		else {
    			Q2.update(1,1,n,1);
    		}
    	  	q[x-y+n]=1;
    	  	if(x-y<=0){
    	  		int k=x-y+n-1;
    	  		ans+=n+(x-y);
    	  		L=n+1-k,R=n+1+k;
    	  		//printf("3--%d ",ans);
    	  		if(L&1)ans-=P.odd_query(1,1,N);
    	  		else ans-=P.n_query(1,1,N);
    		}
    		else{
    			int k=x-y-n+1;
    			ans+=n-(x-y);
    			L=n+1+k,R=n+1-k;
    			//printf("%d %d
    ",L,R);
    			//printf("4--%d ",ans);
    			if(R&1)ans-=P.odd_query(1,1,N);
    			else {
    			ans-=P.n_query(1,1,N);
    	 	    }
    		 }
    	   }
    	}
    	printf("%lld
    ",1ll*n*n-ans);
    }
    int main(){
    	int x,y;
    	ll ans=0;
    	double st=clock();
    	freopen("dat.in","r",stdin);
    	freopen("std.out","w",stdout);
    	read(n),read(m);N=n*2;
        solve();
        double ed=clock();
        printf("%lf
    ",ed-st);
    	return 0;
    }
    

    B

    毒瘤期望,n=4的暴力枚举都及其毒瘤,没时间打

    题解暂时没搞懂

    C

    多项式算了吧,考场上暴力模拟感谢出题人拿了40pts,题解推了一大波东西然后什么阶乘卷积。。。

    贴一份老师的std

    #include<stdio.h>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<cmath>
    #include<string>
    #include<assert.h>
    #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
    #define per(i,j,k) for(int i=(int)j;i>=(int)k;i--)
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    typedef long long LL;
    const int P=998244353;
    const int G=3;
    const int N=310000;
    inline int Pow(int a,int b){
    	int c=1;
    	for(;b;b>>=1,a=a*1ll*a%P)if(b&1)c=c*1ll*a%P;
    	return c;
    }
    int w[2][N];
    int rev[N];
    inline void fft(int *a,int n,int ff){
    	rep(i,0,n-1)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<n;i<<=1)
    	for(int j=0,t=n/(i<<1);j<n;j+=(i<<1))
    	for(int k=0,l=0;k<i;k++,l+=t){
    		int x=a[i+j+k]*1ll*w[ff][l]%P;
    		int y=a[j+k];
    		a[j+k]=(x+y)%P;
    		a[i+j+k]=(y+P-x)%P;
    	}
    	if(ff==1){
    		int v=Pow(n,P-2);
    		rep(i,0,n-1)a[i]=a[i]*1ll*v%P;
    	}
    }
    inline void initfft(int n){
    	rep(i,0,n-1){
    		int x=i;
    		int y=0;
    		for(int k=1;k<n;k<<=1,x>>=1)(y<<=1)|=(x&1);
    		rev[i]=y;
    	}
    	w[0][0]=w[1][0]=1;
    	int V=Pow(G,(P-1)/n);
    	int VV=Pow(V,P-2);
    	rep(i,1,n-1){
    		w[0][i]=w[0][i-1]*1ll*V%P;
    		w[1][i]=w[1][i-1]*1ll*VV%P;
    	}
    }
    int a[N],n;
    int fac[N],inv[N];
    int ans[N];
    inline void init(int n){
    	fac[0]=1;rep(i,1,n)fac[i]=fac[i-1]*1ll*i%P;
    	inv[n]=Pow(fac[n],P-2);per(i,n-1,0)inv[i]=inv[i+1]*1ll*(i+1)%P;
    }
    int main(){
    	init(200000);
    	scanf("%d",&n);
    	assert(1<=n&&n<=100000);
    	rep(i,0,n-1){
    		scanf("%d",&a[i]);
    		assert(0<=a[i]&&a[i]<P);
    	}
    	rep(i,0,n-1)a[i]=a[i]*1ll*fac[i]%P;
    
    	initfft(1<<18);
    	fft(a,1<<18,0);
    	rep(i,0,(1<<18)-1)a[i]=a[i]*1ll*a[i]%P;
    	fft(a,1<<18,1);
    
    	rep(d,0,n-1){
    		ans[d]=a[n-1+d];
    		ans[d]=ans[d]*1ll*Pow(2,d)%P;
    		ans[d]=ans[d]*1ll*inv[d]%P;
    	}
    	rep(i,0,n-1)printf("%d ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    PHP中有多态么
    【Android】九宫格实现
    采用xshell链路本地虚拟机Linux
    读取资源文件的工具.
    dede织梦背景经常使用标签
    PHP第三个教训 PHP基本数据类型
    Linux经常使用的命令(必看)
    易Android登录Demo
    [2013山东ACM]省赛 The number of steps (可能DP,数学期望)
    web开发性能优化---UI接口章
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9427199.html
Copyright © 2011-2022 走看看