zoukankan      html  css  js  c++  java
  • [考试反思]0518省选模拟99:扭曲

    不知道该说啥。

    线段树判断条件

    $r<=r$

    反正把自己气得不轻。$70$的暴力已经会写了最后想写正解然后爆零了。。。

    $T3$数据奇水,模拟直接$AC$(后来加了一组数据然而依然是随便乱搞就能过)

    不重要反正自己没信仰没写模拟。。。也当是长记性了。。。

    $T2$写的纯暴力卡常骗得分倒是也不少。然而并没有什么卵用。

    $T2$真的是好题。。。重学$FWT$了。。。

    T1:矩阵求和

    大意:$n imes m$矩阵,$(i,j)$上写着$(i-1) imes m+j$。支持:交换两行,交换两列,对一个矩形做$k$次二维前缀和之后所有值的和。$k le 10,n,m,q le 10^5$

    首先这样一个矩阵可以分开行列讨论。每个位置的值就是$A_i imes  i + B_j imes j$。

    行列交换就是交换两个$A_i,A_j$或交换两个$B_i,B_j$。

    求答案的时候也只用分开考虑$A,B$的贡献就可以了。问题下降到一维。

    前缀和啥的还是可以组合数解决,答案形式如下:$inom{r-l+k+1}{k+1} sum A_i inom{d-i+k}{k} $

    把后面那个组合数用斯特林数展开。得到一长串式子,至于$A_i imes (-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
    ",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 }
    View Code

    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 = sumlimits_{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 imes 2^m$的矩阵,这个大矩阵里一共也就$2^{k-1}$种值。

    我们不在意这个,我们只关注每一列对位相乘之后的结果。那么也就是$prod (sumlimits_{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} - ...  = sumlimits_{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 }
    View Code

    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 }
    哈希表代码(最大化solve返回值)

    胖头鱼系列出题人还是比较良心的。除了数据有点水(也可能是校内自造的)然后$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
    ",ans);
    63 }
    View Code
  • 相关阅读:
    华硕路由器修改 Hosts 以达到局域网内自定义解析
    一款开源、高颜值的终端terminus,支持Windows、MacOS
    Windows 10启用Linux子系统(WSL)
    一款全能的下载工具Motrix,支持BT、磁力链、百度网盘等资源
    ubuntu 14.04 和16.04 快速下载
    CentOS 7一键安装Seafile搭建私有云存储
    background背景色
    3d爱心代码
    Mac Mini(late 2014) 添加NVMe固态组Fusion Drive
    member access within misaligned address 0x0000002c3931 for type 'struct ListNode‘
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12914683.html
Copyright © 2011-2022 走看看