NOI模拟20220603
看了半天T1不会,拿了60准备跑路,其实是先看的T2,写完了min_25才去看的T1
然后T3似乎吧有那么一点点感觉,但是又找不到头绪,想钦定边容斥,但是想到状态太多了于是走了
后来想T1发现只有log个有用的值,于是就做掉了
T1 石子游戏
这里不在赘述本题做法,只是记录一下FWT只求一个值的做法
我们知道FWT的本质式子是这样的
FWT的话,就直接枚举每一位去加和就好了
问题是IFWT,发现每一个数都要乘上一个因为每次变换都要除以2
T2 函数
据说这个题是哦,意思就是我们要求的数质因数分解之后指数都是2以上,没有1,这样取值个数就只有根号个了
本蒟蒻并没有学过这个东西,于是只能被迫改题
利用狄利克雷卷积,设,这里,可以说这里是个构造了
所以,此时的可以通过拉格朗日插值得到
我们可以倒推,首先可以肯定也是个积性函数,因为满足狄利克雷卷积的必然是积性函数,所以
根据,得到质数处取值是0,即
那么我们看是啥,按照上面的推法,可得对于任意的e都有
所以我们可以搜索得到这根号个取值,最后乘起来就行了
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,但是复杂度有一点点高
考虑如果有一个数没有贴上界,那么其他数任意选,最后补上就行
要是有边,那就容斥就好了,钦定某个边集的两侧都相等,最后加和就是答案
钦定的边集会让点形成一些联通块,大小是偶数的直接乘上值域,奇数的记录下来最后用上面的东西
设表示选了s集合的点,其中奇数连通块的值域集合是t
似乎状态是的,转移时,好像寄了,但是每次转移枚举的集合必须包含最小的那个不存在的点,于是好像复杂度就对了
这里写一下,这个数组不太好开,用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;
}
本文作者:fengwu2005
本文链接:https://www.cnblogs.com/hzoi-fengwu/p/16355641.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】