NOI模拟20220603

看了半天T1不会,拿了60准备跑路,其实是先看的T2,写完了min_25才去看的T1

然后T3似乎吧有那么一点点感觉,但是又找不到头绪,想钦定边容斥,但是想到状态太多了于是走了

后来想T1发现只有log个有用的值,于是就做掉了

T1 石子游戏

这里不在赘述本题做法,只是记录一下FWT只求一个值的\(O(n)\)做法

我们知道FWT的本质式子是这样的

\[[x^n]FWT(F)=\large\sum\limits_{i}(-1)^{\text{pop_coun(i&n)}}[x^i]F \]

FWT的话,就直接枚举每一位去加和就好了

问题是IFWT,发现每一个数都要乘上一个\(2^{-log(n)}\)因为每次变换都要除以2

T2 函数

据说这个题是\(Powerful\ number\)哦,意思就是我们要求的数质因数分解之后指数都是2以上,没有1,这样取值个数就只有根号个了

本蒟蒻并没有学过这个东西,于是只能被迫改题

利用狄利克雷卷积,设\(F=G*H\),这里\(G(i)=i^k\),可以说这里是个构造了

所以\(Ans=\sum\limits_{i=1}^{n}H(i)\sum\limits_{j<=n/i}G(j)\),此时的\(G\)可以通过拉格朗日插值得到

我们可以倒推\(H\),首先可以肯定\(H\)也是个积性函数,因为满足狄利克雷卷积的必然是积性函数,所以\(H(1)=1\)

根据\(F(p)=H(p)*G(1)+G(P)*H(1)\),得到质数处取值是0,即\(H(p)=0\)

那么我们看\(H(p^e)\)是啥,按照上面的推法,可得对于任意的e都有\(H(p^e)=p^k-p^{2k}\)

所以我们可以搜索得到这根号个取值,最后乘起来就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=4e6+5;
const int mod=1e9+7;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,sq;
int p[N],cnt,pw[N];bool vis[N];
void init_p(){
    fo(i,2,sq){
        if(!vis[i])p[++cnt]=i,pw[cnt]=ksm(i,m);
        for(int j=1;j<=cnt&&i*p[j]<=sq;j++){
            vis[i*p[j]]=true;
            if(i%p[j]==0)continue;
        }
    }
}
int xx[30],yy[30],xs[30],tx1[30],tx2[30];
void lglr(int *x,int *y,int c){
    fo(i,0,c){
        fo(k,0,c)tx1[k]=0;tx1[0]=1;
        fo(j,0,c)if(i!=j){
            fo(k,0,c)tx2[k]=tx1[k]*(mod-x[j])%mod;
            fu(k,c,1)tx1[k]=tx1[k-1];tx1[0]=0;
            fo(k,0,c)tx1[k]=(tx1[k]+tx2[k])*ksm(x[i]-x[j]+mod,mod-2)%mod;
        }
        fo(k,0,c)xs[k]=(xs[k]+tx1[k]*y[i])%mod;
    }
}
int get(int x){
    int nw=1,ret=0;x%=mod;
    fo(i,0,m+1)ret=(ret+nw*xs[i])%mod,nw=nw*x%mod;
    return ret;
}
int S(int x,int i){
    int ret=get(n/x);
    for(int j=i+1;j<=cnt&&p[j]*p[j]<=n/x;j++){
        for(int c=2,nw=p[j]*p[j];nw<=n/x;c++,nw*=p[j]){
            ret=(ret+(pw[j]-pw[j]*pw[j]%mod+mod)*S(x*nw,j))%mod;
        }
    }
    return ret;
}
signed main(){
    n=read();m=read();sq=sqrt(n);
    fo(i,0,m+1){
        xx[i]=i;
        fo(j,0,i)yy[i]=(yy[i]+ksm(j,m))%mod;
    }init_p();lglr(xx,yy,m+1);
    printf("%lld\n",S(1,0));
}

T3 画

首先考虑没有连边的情况,可以数位dp,但是复杂度有一点点高

考虑如果有一个数没有贴上界,那么其他数任意选,最后补上就行

要是有边,那就容斥就好了,钦定某个边集的两侧都相等,最后加和就是答案

钦定的边集会让点形成一些联通块,大小是偶数的直接乘上值域,奇数的记录下来最后用上面的东西

\(f_{s,t}\)表示选了s集合的点,其中奇数连通块的值域集合是t

似乎状态是\(3^n\)的,转移时\(2^i\),好像寄了,但是每次转移枚举的集合必须包含最小的那个不存在的点,于是好像复杂度就对了

这里写一下,这个数组不太好开,用hash_table太拉了

于是我们发现三进制的s+t恰好不重不漏的取遍所有的数,于是...

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=(1<<15);
const int mod=998244353;
const int inf=0x3f3f3f3f3f3f3f3f;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,C,lm[20],lim[20];
int d[20][20];
namespace DP{
    int u,nn,ans,dp[20][2][2];
    int sol(int tp=0){
        int ret=0,al=0;
        fu(o,60,0){al+=(1ll<<o);
            fo(i,0,nn)fo(j,0,1)fo(k,0,1)dp[i][j][k]=0;
            dp[0][0][0]=1;
            fo(i,1,nn)fo(j,0,1)fo(k,0,1)if(dp[i-1][j][k]){
                int nw=lim[i]>>o&1;
                // if(tp==1&&o<5)cerr<<o<<" "<<i-1<<" "<<j<<" "<<k<<" "<<nw<<" "<<ret<<endl;
                if(!j){
                    dp[i][j][k^nw]=(dp[i][j][k^nw]+dp[i-1][j][k]*((lim[i]-(lim[i]&al)+1)%mod))%mod;
                    if(nw)dp[i][1][k]=(dp[i][1][k]+dp[i-1][j][k])%mod;
                }
                else {
                    dp[i][j][k^nw]=(dp[i][j][k^nw]+dp[i-1][j][k]*((lim[i]-(lim[i]&al)+1)%mod))%mod;
                    if(nw)dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k]*((1ll<<o)%mod))%mod;
                }
            }
            ret=(ret+dp[nn][1][C>>o&1])%mod;
            if(!dp[nn][0][C>>o&1]){break;}
            else ret=(ret+!o)%mod;
        }return ret;
    }
    signed g[1<<15],ms[1<<15],mi[1<<15],sm[1<<15],ys[1<<15];
    signed f[20000005],p[1<<15],pw[16];
    int ff(int s,int t){return p[s]+p[t];}
    vector<signed> vec[20];
    int lb(int x){return x&-x;}
    signed main(){
        fo(i,1,n)ys[1<<i-1]=i;
        fo(s,0,(1<<n)-1)fo(i,1,n)if(s>>i-1&1)fo(j,i+1,n)if(s>>j-1&1)ms[s]+=d[i][j];
        fo(s,1,(1<<n)-1){
            sm[s]=sm[s>>1]+(s&1);
            g[s]=(ms[s]==0);int mn=ys[lb(s)];vec[mn].push_back(s);
            // if(g[s])cerr<<g[s]<<" ";
            for(int t=(s-1)&s;t;t=(t-1)&s)if((t>>mn-1&1)){
                // cerr<<g[s]<<" ";
                g[s]=(g[s]-1ll*g[t]*(ms[s^t]==0)+mod)%mod;
                // if(g[t])cerr<<t<<" ";
            }
            // if(g[s])cerr<<s<<" "<<g[s]<<endl;
        }
        // cerr<<"SB"<<endl;
        pw[0]=1;fo(i,1,n)pw[i]=pw[i-1]*3;
        fo(s,0,(1<<n)-1)fo(i,1,n)if(s>>i-1&1)p[s]+=pw[i-1];
        fo(s,1,(1<<n)-1){
            int now,vl=inf;
            fo(i,1,n)if(s>>i-1&1)if(lm[i]<vl)now=i,vl=lm[i];
            mi[s]=now;
        }
        f[ff(0,0)]=1;
        fo(s,0,(1<<n)-1){
            for(int t=s;;t=(t-1)&s){
                if(f[ff(s,t)])for(int o:vec[ys[lb(((1<<n)-1)^s)]])if(g[o]&&!(o&s)){
                    if(sm[o]&1)f[ff(s|o,t|(1<<mi[o]-1))]=(f[ff(s|o,t|(1<<mi[o]-1))]+1ll*f[ff(s,t)]*g[o]%mod)%mod;
                    else f[ff(s|o,t)]=(f[ff(s|o,t)]+1ll*f[ff(s,t)]*g[o]%mod*(lm[mi[o]]%mod+1)%mod)%mod;
                }
                if(!t)break;
            }
        }
        // cerr<<"FK"<<endl;
        fo(s,0,(1<<n)-1)if(f[ff((1<<n)-1,s)]){
            nn=0;fo(i,1,n)if(s>>i-1&1)lim[++nn]=lm[i];u=(1<<nn)-1;
            if(!s)ans=(ans+f[ff((1<<n)-1,s)]*(C==0))%mod;
            else ans=(ans+1ll*f[ff((1<<n)-1,s)]*sol())%mod;
        }
        printf("%lld\n",ans);
        return 0;
    }
}
signed main(){
    n=read();m=read();C=read();
    fo(i,1,n)lm[i]=read();
    fo(i,1,m){
        int x=read(),y=read();
        d[x][y]=d[y][x]=1;
    }
    // cerr<<inf<<endl;
    return DP::main();
    return 0;
}
posted @ 2022-06-08 14:44  fengwu2005  阅读(26)  评论(0编辑  收藏  举报