版權緣由不提供題面信息git
這幾天做息有點鬼畜,雖然昨晚很晚睡可是早上精神還不錯,看到題發現T1很友好?T2woc這暴力都好難打?T3多項式?!這樣下去比賽會不會出現更多高端操做,恐怕涼涼spa
感謝出題人,暴力好打分又多,正解也不難想,這題基本上部分分都打了一遍調試
#### 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; }
發現每一個左斜行能肯定的右斜行的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; }
毒瘤指望,n=4的暴力枚舉都及其毒瘤,沒時間打class
題解暫時沒搞懂date
多項式算了吧,考場上暴力模擬感謝出題人拿了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; }