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;
}