不知道該說啥。
線段樹判斷條件
$r<=r$
反正把自己氣得不輕。$70$的暴力已經會寫了最後想寫正解然後爆零了。。。
$T3$數據奇水,模擬直接$AC$(後來加了一組數據然而依然是隨便亂搞就能過)
不重要反正自己沒信仰沒寫模擬。。。也當是長記性了。。。
$T2$寫的純暴力卡常騙得分倒是也不少。然而並沒有什麼卵用。
$T2$真的是好題。。。重學$FWT$了。。。
T1:矩陣求和
大意:$n \times m$矩陣,$(i,j)$上寫着$(i-1)\times m+j$。支持:交換兩行,交換兩列,對一個矩形做$k$次二維前綴和之後所有值的和。$k \le 10,n,m,q \le 10^5$
首先這樣一個矩陣可以分開行列討論。每個位置的值就是$A_i \times i + B_j \times j$。
行列交換就是交換兩個$A_i,A_j$或交換兩個$B_i,B_j$。
求答案的時候也只用分開考慮$A,B$的貢獻就可以了。問題下降到一維。
前綴和啥的還是可以組合數解決,答案形式如下:$\binom{r-l+k+1}{k+1} \sum A_i \binom{d-i+k}{k} $
把後面那個組合數用斯特林數展開。得到一長串式子,至於$A_i \times (-i)^x$有關。對於所有$x \le k$都線段樹維護出來就好了。
單點修改區間查詢。總時間複雜度$O(qklogn+qk^2)$
1 #include<cstdio> 2 const int mod=1000000007,S=100055; 3 int mo(int x){return x>=mod?x-mod:x;} 4 int n,m,q,A[S],B[S],C[S][12],st[12][12],pw[S][12],inv[12],Q[11]; char s[5]; 5 struct T{int w[12];}aT[S<<2],bT[S<<2]; 6 #define md (L+R>>1) 7 #define lc p<<1 8 #define rc lc|1 9 void build(T*t,int v,int x,int p,int L,int R){ 10 if(L==R){ 11 t[p].w[0]=v; 12 for(int i=1;i<11;++i)t[p].w[i]=t[p].w[i-1]*(0ll+mod-L)%mod; 13 return; 14 }if(x<=md)build(t,v,x,lc,L,md);else build(t,v,x,rc,md+1,R); 15 for(int i=0;i<11;++i)t[p].w[i]=mo(t[lc].w[i]+t[rc].w[i]); 16 } 17 void geT(T*t,int l,int r,int p,int L,int R){ 18 if(l<=L&&R<=r){for(int i=0;i<11;++i)Q[i]=mo(Q[i]+t[p].w[i]);return;} 19 if(l<=md)geT(t,l,r,lc,L,md); if(r>md)geT(t,l,r,rc,md+1,R); 20 } 21 int main(){ 22 scanf("%d%d%d",&n,&m,&q); 23 for(int i=2;i<=n;++i)A[i]=mo(A[i-1]+m),build(aT,A[i],i,1,1,n); 24 for(int i=1;i<=m;++i)B[i]=i,build(bT,i,i,1,1,m); 25 for(int i=0;i<S;++i)for(int j=C[i][0]=1;j<=i&&j<12;++j)C[i][j]=mo(C[i-1][j-1]+C[i-1][j]); 26 for(int i=0;i<S;++i)for(int j=pw[i][0]=1;j<12;++j)pw[i][j]=pw[i][j-1]*1ll*i%mod; 27 for(int i=st[0][0]=1;i<12;++i)for(int j=1;j<12;++j)st[i][j]=(st[i-1][j]*(i-1ll)+st[i-1][j-1])%mod; 28 inv[0]=inv[1]=1; 29 for(int i=2;i<12;++i)inv[i]=mod-mod/i*1ll*inv[mod%i]%mod; 30 for(int i=2;i<12;++i)inv[i]=1ll*inv[i-1]*inv[i]%mod; 31 for(int _=0,l,r,u,d,k,ans;_<q;++_){ 32 scanf("%s%d%d",s,&u,&l); 33 if(s[0]=='Q'){ 34 scanf("%d%d%d",&d,&r,&k); ans=0; 35 for(int i=0;i<11;++i)Q[i]=0; 36 geT(aT,u,d,1,1,n); 37 for(int s=0;s<=k;++s)for(int j=s;j<=k;++j)ans=(ans+1ll*pw[d+k][s]*st[k][j]%mod*(k-j&1?mod-1:1)%mod*C[j][s]%mod*Q[j-s]%mod*inv[k]%mod*C[r-l+k+1][k+1])%mod; 38 for(int i=0;i<11;++i)Q[i]=0; 39 geT(bT,l,r,1,1,m); 40 for(int s=0;s<=k;++s)for(int j=s;j<=k;++j)ans=(ans+1ll*pw[r+k][s]*st[k][j]%mod*(k-j&1?mod-1:1)%mod*C[j][s]%mod*Q[j-s]%mod*inv[k]%mod*C[d-u+k+1][k+1])%mod; 41 printf("%d\n",ans); 42 }else if(s[0]=='R')A[u]^=A[l]^=A[u]^=A[l],build(aT,A[u],u,1,1,n),build(aT,A[l],l,1,1,n); 43 else B[u]^=B[l]^=B[u]^=B[l],build(bT,B[u],u,1,1,m),build(bT,B[l],l,1,1,m); 44 } 45 }
T2:西行寺無餘涅槃
大意:有$k$類菜,每類有$a_i$種。有$n$天。第$i$天吃第$j$類菜有$p_{i,j}$愉悅度(可以有很多天都同一種菜)。總愉悅度是每天愉悅度的異或和。
$p_{i,j} <2^m$。求對於$\forall i <2^m$,$n$天下來愉悅度恰好是這個值的方案數。$m+k \le 20,n \le 10^6,k \le 10$
注意下邊菜的編號範圍是$[0,k)$
不難想到暴力,直接對於每一天搞一個生成函數然後暴力$xorFWT$,對位累乘然後再IDFT$回來。
還有一個微小的優化,我們把所有的$p_{i,j}$都異或上$p_{i,0}$最後求答案時再異或回來,這樣可以讓$k$的範圍縮小$1$
這裏生成函數很特殊,係數表達中,只有$a_0,a_1,a_2...a_{k-1}$這$k$種值。
考慮$xorFWT$的本質$FWT(A)_i = \sum\limits_{j=0}^{len-1} (-1)^{popcnt(i \& j)} A_j$
也就是說每個數的貢獻係數要麼是$1$要麼是$-1$。因爲我們把所有數都異或$p_{i,0}$了,所以$p_{i,0}$現在就是$0$
也就是說$a_0$的貢獻係數一定是$1$,剩下的貢獻係數是$1$或$-1$。一共$2^{k-1}$種取值。
我們把$n$個多項式點值寫成一個$n \times 2^m$的矩陣,這個大矩陣裏一共也就$2^{k-1}$種值。
我們不在意這個,我們只關注每一列對位相乘之後的結果。那麼也就是$\prod (\sum\limits_{j=0}^{k} (-1)^{y_j} a_j)^{x_i}$
也就是,對於$2^m$列中的每一列$i$,我們也只在意$2^{k-1}$種取值$j$的出現次數$x_{i,j}$。然後就可以做累乘了。
首先,我們有$x_{i,0}+x_{i,1}+...+x_{i,2^{k-1}-1}=n$。原因比較顯然。
然後,考慮$FWT$的本質。我們新建一個都爲$0$的多項式$A$,對於所有$y \in [1,n]$,都執行$A_{p_{y,1}}++$
對這個東西進行$xorFWT$會得到什麼?根據$xorFWT$本質的那個式子,我們知道:
$FWT(A)_i= x_{i,0} - x_{i,1} + x_{i,2} - ... = \sum\limits_{z=0}^{2^{k-1}-1} (-1)^{popcnt(z \& 1)} x_{i,z}$
同理可以每次使得$A_{p_{y,2}}++$,或者使$A_{p_{y,1} \ xor \ p_{y,2}}++$。每一次都能列出$2^m$個方程。
這樣,對於每一列$i$,我們都可以得到$2^{k-1}$個方程。問題在於解方程。
$$
x_{i,0}+x_{i,1}+x_{i,2}+x_{i,3}+...=n \\
x_{i,0}-x_{i,1}+x_{i,2}-x_{i,3}+...=FWT(A_1)_i \\
x_{i,0}+x_{i,1}-x_{i,2}-x_{i,3}+...=FWT(A_2)_i \\
x_{i,0}-x_{i,1}-x_{i,2}+x_{i,3}+...=FWT(A_3)_i \\
...
$$
可以發現左邊這一攤就是一個非常經典的$xorFWT$形式。所以對右邊的東西構造多項式然後IFWT$就可以得到所有$x_i$
時間複雜度$O(2^{k-1}k(n+2^m))$。然而實際運行很快。
1 #include<cstdio> 2 char s[100000000],*I=s; 3 void In(int&x){x=0;while(*I<48||*I>59)I++;while(*I>47&&*I<58)x=x*10+*I++-48;} 4 const int mod=998244353; 5 int len,p[1000005][11],n,m,k,T,A[1048576],B[1048576],*b=B,c[11],C[2333],ans[1048576]; 6 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 7 int mo(int x){return x>=mod?x-mod:x;} 8 void FWT(int*a,int op=0){ 9 for(int i=1;i<len;i<<=1)for(int j=0;j<len;j+=i<<1)for(int k=j,x,y;k<j+i;++k) 10 x=a[k],y=a[k+i],a[k]=mo(x+y),a[k+i]=mo(mod+x-y); 11 if(op)for(int i=0,iv=qp(len,mod-2);i<len;++i)a[i]=a[i]*1ll*iv%mod; 12 } 13 int main(){ 14 fread(s,1,100000000,stdin); In(n);In(m);In(k); 15 for(int i=0;i<k;++i)In(c[i]); 16 for(int i=0;i<1<<k-1;++i)for(int j=0;j<k;++j)if(i&1<<j-1)C[i]=mo(C[i]-c[j]+mod);else C[i]=mo(C[i]+c[j]); 17 for(int i=1;i<=n;++i)for(int j=0;j<k;++j)In(p[i][j]); 18 for(int i=1;i<=n;++i)for(int j=1;j<k;++j)p[i][j]^=p[i][0]; 19 for(int i=1;i<=n;++i)T^=p[i][0]; 20 len=1<<m; 21 for(int S=1;S<1<<k-1;++S){ 22 for(int i=1,x;x=0,i<=n;++i){ 23 for(int j=1;j<k;++j)if(S>>j-1&1)x^=p[i][j]; 24 A[x]++; 25 }FWT(A); 26 for(int i=0;i<1<<m;++i)B[i<<k-1|S]=A[i],A[i]=0; 27 } 28 len=1<<k-1; 29 for(int S=0;S<1<<m;++S){ 30 b[0]=n;FWT(b,1); ans[S]=1; 31 for(int i=0;i<1<<k-1;++i)ans[S]=1ll*ans[S]*qp(C[i],b[i])%mod; 32 b+=len; 33 }len=1<<m;FWT(ans,1); 34 for(int i=0;i<1<<m;++i)printf("%d ",ans[i^T]); 35 }
T3:魚貫而入
大意:問把$n$個$a_i$插入哈希表,自取$len \ge n$。最大撞上的次數是多少。$n \le 200,A_i \le 10^{18}$
1 void add_fish(long long &cnt, long long x, long long len){ 2 long long y = x % len; 3 while(h[y] != -1 && h[y] != x) 4 y = (y + 1) % len, cnt++; 5 h[y] = x; 6 } 7 long long solve(long long len){ 8 for (int i=0; i< len; i ++) h[i]=-1 9 long long cnt = 0; 10 for (int i = 1; i <= n; i ++) add_fish(cnt, a[i], len); 11 return cnt; 12 }
胖頭魚系列出題人還是比較良心的。除了數據有點水(也可能是校內自造的)然後$std$有點鍋(應該不是校內自造的)
首先,爲了讓有魚撞上,你一定會選擇某個$|A_i - A_j|$的因子作爲$len$。
發現選擇合數一定不優,所以我們會選擇質數。但是如果質數小於$n$那又不合法。
所以我們的決策是:所有$>n^2$的質數,以及所有$\in [n,n^2]$的數。
對於$>n^2$的合數,如果可以分割出一個小於$n$的質數就可以遞歸考慮。
如果分割不出的話那麼所有質因子都大於$n$,也會在質因子除被考慮。
寫個$Pollard-Rho$分解質因數。然後$check$的話暴力$check$就行。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 unordered_set<ll>S; 5 int n,r[222],ans;ll a[222]; 6 ll mo(ll x,ll m){return x>=m?x-m:x;} 7 ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} 8 ll mul(ll x,ll y,ll m){return x<=2000000000&&y<=2000000000?x*y%m:mo((x*y-(ll)(1.L*x/m*y)*m)%m+m,m);} 9 ll qp(ll b,ll t,ll m,ll a=1){for(;t;t>>=1,b=mul(b,b,m))if(t&1)a=mul(a,b,m);return a;} 10 bool MR(ll x,int b){ ll k=x-1,y; 11 while(!(k&1)){ 12 if((y=qp(b,k,x))!=1)return y==x-1; 13 k>>=1; 14 }return 1; 15 } 16 bool pr(ll x){ 17 if(x==2||x==3||x==5||x==7||x==11||x==13||x==61)return 1; 18 if(x==1||x%2==0||x%3==0||x%5==0||x%7==0||x%11==0||x%13==0)return 0; 19 return MR(x,2)&&MR(x,11)&&MR(x,61); 20 } 21 ll PR(ll x){ 22 ll s=0,t=0,c=rand()%(x-1)+1,p=1,d; 23 for(int g=1;;g<<=1,s=t,p=1){ 24 for(int _=1;_<=g;++_){ 25 t=mo(mul(t,t,x)+c,x); p=mul(p,abs(t-s),x); 26 if(_%127==0){d=gcd(x,p);if(d>1)return d;} 27 }d=gcd(x,p);if(d>1)return d; 28 } 29 } 30 void Div(ll x){ 31 if(x<n)return; 32 if(pr(x)){S.insert(x);return;} 33 ll y=PR(x);Div(y);Div(x/y); 34 } 35 const int m=10000003;bool al[m];ll usd[222]; 36 struct hash_map{ 37 int fir[m],l[233],ec; ll to[233]; 38 bool f(ll x){int r=x%m; 39 for(int i=fir[r];i;i=l[i])if(to[i]==x)return 1; 40 l[++ec]=fir[r];fir[r]=ec;to[ec]=x;return 0; 41 }void clear(){while(ec)fir[to[ec--]%m]=0;} 42 }M; 43 int chk(ll d,int A=0){ 44 if(d<=m){ 45 for(int i=1;i<=n;++i){ 46 int x=a[i]%d; while(al[x])x=x==d-1?0:x+1,A++; 47 al[x]=1; usd[i]=x; 48 }for(int i=1;i<=n;++i)al[usd[i]]=0; 49 }else{ 50 for(int i=1;i<=n;++i){ 51 ll x=a[i]%d; 52 while(M.f(x))x=x==d-1?0:x+1,A++; 53 }M.clear(); 54 }return A; 55 } 56 int main(){ 57 scanf("%*d%d",&n); 58 for(int i=1;i<=n;++i)scanf("%lld",&a[i]); 59 for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)Div(abs(a[i]-a[j])); 60 for(int i=n;i<=n*n;++i)S.insert(i); 61 for(auto x:S)ans=max(ans,chk(x)); 62 printf("%d\n",ans); 63 }