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\n",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\n",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\n",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\n",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\n",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;
}

posted @ 2018-08-05 21:13  Rye_Catcher  阅读(244)  评论(0编辑  收藏  举报