[家里训练20_02_12]ABC

A:CF1119H加强版,k<=10。

不太想解释。

  1 #define mod 998244353
  2 #define G2 499122177
  3 #include<bits/stdc++.h>
  4 using namespace std;
  5 typedef long long int ll;
  6 int n,m,k,a[55],p[1000005][11],mask;
  7 ll f[1<<21],**g,val[1<<21];
  8 inline ll qpow(ll x,ll y)
  9 {
 10     ll ans=1,base=x;
 11     while(y)
 12     {
 13         if(y&1)
 14             ans=ans*base%mod;
 15         base=base*base%mod;
 16         y>>=1;
 17     }
 18     return ans;
 19 }
 20 inline void FWT(ll*A,int limit)
 21 {
 22     for(int len=2;len<=limit;len<<=1)
 23         for(int i=0;i<limit/len;++i)
 24             for(int j=0;j<len/2;++j)
 25             {
 26                 ll x=A[i*len+j],y=A[i*len+j+len/2];
 27                 A[i*len+j]=(x+y)%mod;
 28                 A[i*len+j+len/2]=(x-y+mod)%mod;
 29             }
 30 }
 31 inline void IFWT(ll*A,int limit)
 32 {
 33     for(int len=2;len<=limit;len<<=1)
 34         for(int i=0;i<limit/len;++i)
 35             for(int j=0;j<len/2;++j)
 36             {
 37                 ll x=A[i*len+j],y=A[i*len+j+len/2];
 38                 A[i*len+j]=(x+y)%mod*G2%mod;
 39                 A[i*len+j+len/2]=(x-y+mod)%mod*G2%mod;
 40             }
 41 }
 42 int main()
 43 {
 44     ios::sync_with_stdio(false);
 45     cin>>n>>m;
 46     k=3;
 47     for(int i=0;i<k;++i)
 48         cin>>a[i];
 49     for(int i=1;i<=n;++i)
 50     {
 51         for(int j=0;j<k;++j)
 52             cin>>p[i][j];
 53         mask^=p[i][0];
 54         for(int j=1;j<k;++j)
 55             p[i][j]^=p[i][0];
 56     }
 57     g=new ll*[1<<m];
 58     for(int i=0;i<(1<<m);++i)
 59     {
 60         g[i]=new ll[1<<(k-1)];
 61         for(int j=0;j<(1<<(k-1));++j)
 62             g[i][j]=0;
 63         g[i][0]=n;
 64     }
 65     for(int i=0;i<k;++i)
 66         val[0]=(val[0]+a[i])%mod;
 67     for(int S=1;S<(1<<(k-1));++S)
 68     {
 69         for(int i=0;i<(1<<m);++i)
 70             f[i]=0;
 71         val[S]=a[0];
 72         for(int j=0;j<k-1;++j)
 73             if(S&(1<<j))
 74                 val[S]=(val[S]-a[j+1]+mod)%mod;
 75             else
 76                 val[S]=(val[S]+a[j+1])%mod;
 77         for(int i=1;i<=n;++i)
 78         {
 79             int s=0;
 80             for(int j=0;j<k-1;++j)
 81                 if(S&(1<<j))
 82                     s^=p[i][j+1];
 83             ++f[s];
 84         }
 85         FWT(f,1<<m);
 86         for(int i=0;i<(1<<m);++i)
 87             g[i][S]=f[i];
 88     }
 89     ll G=qpow(1<<(k-1),mod-2);
 90     for(int i=0;i<(1<<m);++i)
 91     {
 92         IFWT(g[i],1<<(k-1));
 93         ll ans=1;
 94         for(int S=0;S<(1<<(k-1));++S)
 95             ans=ans*qpow(val[S],g[i][S])%mod;
 96         f[i]=ans;
 97     }
 98     IFWT(f,1<<m);
 99     for(int i=0;i<(1<<m);++i)
100         cout<<f[i^mask]<<" ";
101     cout<<endl;
102     return 0;
103 }
View Code

B:给一个n*m的矩阵,一行一行从左到右编号依次加一直到n*m。有如下操作:

1.交换x、y行。

2.交换x、y列。

3.询问某一个子矩阵的k次前缀和的和。

n,m,q<=100000,k<=10。

我们不可能直接维护整个矩阵,所以一定是把矩阵拆成两维分别维护。

​ 原来的第i行j列的值是$(i-1)*m+j$,我们可以把它理解成$a_i+b_j$。交换某一行或某一列时,相当于交换$a$或$b$中的两个元素。

​ 观察子矩阵中的每一个元素对于一个询问的贡献,可以发现每个格子的系数相当于从这个格子出发走$k+1$步到达右下角(即$(x_2,y_2)$)的方案数,每次可以走到两维坐标都大于等于它的一个格子(包括自己)。由此可知两维系数是独立的,对于一个格子$(i,j)$其系数可以写成$c_i*d_j$的形式,因为格子的两维坐标增大是互不影响的。而$c_i,d_i$就是在一维的坐标中,每次往右走若干步,走$k+1$次走到某一个端点的方案数。用插板法可得其为$inom{x+k}{k}$,其中$x$是到这个端点的距离。

​ 最终的答案是
$$
sum_{i=x1}^{x2}sum_{j=y1}^{y2}c_id_j(a_i+b_j)
$$

$$
=(sum_{i=x1}^{x2}c_ia_i)(sum_{j=y1}^{y2}d_j)+(sum_{i=x1}^{x2}c_i)(sum_{j=y1}^{y2}d_jb_j)
$$
暴力计算这个式子,一个询问就可以$O(n+m)$求出答案。

易得$c_i=inom{k+x_2-i}{k}=frac{(k+x_2-i)!}{k!(x2-i)!}=frac{1}{k!}(k+x_2-i)^{underline{k}}$

我们知道
$$
x^{underline{n}}=sum_{i=0}^n(-1)^{n-i}s(n,i)x^i
$$
其中$s(n,i)$是第一类斯特林数

将这个下降幂套进去
$$
(k+x_2-i)^{underline{k}}=sum_{d=0}^k(-1)^{k-d}s(k,d)(k+x_2-i)^d
$$

$$
=sum_{d=0}^k(-1)^{k-d}s(k,d)sum_{e=0}^dinom{d}{e}(x_2+k)^e(-i)^{d-e}
$$

如果把$x_2,k$看成参数,这是一个关于$i$的$k$次多项式。

我们只要对于0~10维护$sum a_i imes i^k$就好了(当然,有些细节不同,仍需推式子)。对于另一维同理。修改就是交换$a_x,a_y$。

其实我们不需要推式子,我们只要知道系数是关于$i$的$k$次多项式,你可以暴力拆解所有的因式,就可以得到这些系数。

$c_i=inom{k+x_2-i}{k}=frac{(k+x_2-i)!}{k!(x2-i)!}=frac{1}{k!}(k+x_2-i)^{underline{k}}$

展开这个下降幂,可得

$(k+x_2-i)^{underline{k}}=(k+x_2-i)(k+x_2-i-1)(k+x_2-i-2)...$

将其看成关于$i$和$x_2$的二元多项式,对于每个k预处理一下这些多项式每一项的系数,询问时把$x_2$代进去。

​ 一次修改复杂度是$O(klogn)$的,询问是$O(k^2+klogn)$的


C:有如下代码:

void add_fish(long long &cnt, long long x, long long len) {
	long long y = x % len;
	while(h[y] != -1 && h[y] != x)
		y = (y + 1) % len, cnt ++;
	h[y] = x;
}
long long solve(long long len) {
	for(int i = 0; i < len; i ++) h[i] = -1;
	long long cnt = 0;
	for(int i = 1; i <= n; i ++) add_fish(cnt, a[i], len);
	return cnt;
}

现在给出数组a,问在long long范围内,solve的返回值最大为多少?

原文地址:https://www.cnblogs.com/GreenDuck/p/12300758.html