ZROI-Day2比賽解題報告

ZROIDay2-比賽解題報告

版權緣由不提供題面信息git


這幾天做息有點鬼畜,雖然昨晚很晚睡可是早上精神還不錯,看到題發現T1很友好?T2woc這暴力都好難打?T3多項式?!這樣下去比賽會不會出現更多高端操做,恐怕涼涼spa

A

感謝出題人,暴力好打分又多,正解也不難想,這題基本上部分分都打了一遍調試

#### 50pts
對於每個炮將其所在的所在的交叉行(暫且這麼說)\(O(1)\) 標記,而後\(O(N^2)\)遍歷一遍統計就行了code

#### 70pts
核心思想是計算出放一個炮新增的貢獻,即它能覆蓋的點數減去已經覆蓋的點數,最後\(N^2\)減去總和既是答案get

拿這部分分還花了很多功夫,終於運用人類智慧找出一些規律,也就是對於一個炮\((x,y)\),它左斜行和右斜行能覆蓋的點的個數,而後又發現對於一個肯定的左斜行(即肯定的\(x+y\)),能夠經過\(x,y\)計算出與它有公共點的左斜行的\(x-y\)的相關信息,因而新增一個炮,在他所在的左斜行加上+1標記,加上左斜行覆蓋點數,在枚舉與左斜行有公共點的右斜行,假設這個右斜行已有標記,則貢獻-1。對於右斜行也相似string

#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)\)it

而後鬼畜的是剛碼完大樣例過不了,覺得是奇偶數搞錯,魔改了半天后發現有一個斷定沒寫到循環裏。。。而後又魔改仍是不對,因而開始對拍手動gdb調試,發現有一顆線段樹操做的上限由於是x+y要設成\(2n\),查完這個錯後據考試結束還有不到半小時,真TM刺激io

#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的暴力枚舉都及其毒瘤,沒時間打class

題解暫時沒搞懂date

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;
}
相關文章
相關標籤/搜索