2019年7月26日(数学DP)
Posted alanallen21love28
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019年7月26日(数学DP)相关的知识,希望对你有一定的参考价值。
难受,爆零!!
哎……讲题吧
prob1:A
题目大意:两种操作:把某数二进制上某一位翻转或异或一个集合中的一个数,求从\(s\)变到\(t\)的最少步数
\(sb\)题,完完全全的水题,结果\(bfs\)的队列写萎了
第一种操作可以转成第二种,而每个数最多只被异或一次,一通\(bfs\)瞎搞就可以了。但最小步数更新需在入队时,并将是否更新作为入队条件,否则会\(T,RE\)炸掉(别问我怎么知道的)
贴代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define int long long
#define xx 270000
const int mod=998244353;
inline int read()
int x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
int que[xx][3];
int q[xx],all,ans[xx];
inline void bfs()
int head=0,tail=-1;
que[++tail][0]=0;
que[tail][1]=0;
que[tail][2]=0;
while(head<=tail)
int w=que[head][0],u=que[head][1],v=que[head++][2];
fur(i,w+1,all)
if(!ans[u^q[i]])
que[++tail][0]=i;
que[tail][1]=u^q[i];
ans[u^q[i]]=v+1;
que[tail][2]=v+1;
signed main()
int t=in;
q[1]=1;
fur(i,2,18) q[i]=q[i-1]<<1;
while(t--)
int n=in,m=in;all=18;
fur(i,1,n) q[++all]=in;
int res=0;
memset(ans,0,sizeof(ans));
bfs();
ans[0]=0;
fur(i,1,m)
int s=in,tt=in;
res=(res+i*ans[s^tt]%mod)%mod;
printf("%lld\n",res);
return 0;
prob2:B
题目大意:给定一串字符串(仅存在英文26个字母),求最短的中字典序最小的非子序列字符串
开始以为是字符串题,后来以为是图论题,怎么都没想到是贪心+\(DP\)题(学姐狠啊),当字符串大小小于26时,可以很清楚得到答案,通过此性质从后往前\(DP\):
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define xx 500010
#define inf 0x7fffffff
int f[xx][27],g[xx],pos[xx],n;
char ch[xx];
inline void dfs(int q,int len)
if(len==1)
fur(i,1,26)
if(f[q][i]==n+1)
printf("%c",i+'a'-1);
return;
fur(i,1,26)
if(g[f[q][i]]==len)
printf("%c",i+'a'-1);
dfs(f[q][i]+1,len-1);
break;
int main()
scanf("%s",ch+1);
n=strlen(ch+1);
fur(i,1,26) f[n+1][i]=n+1,pos[i]=n+1;
g[n+1]=1;
fdr(i,n,1)
fur(j,1,26) f[i][j]=f[i+1][j];
f[i][ch[i]-'a'+1]=i;
g[i]=inf;
fur(j,1,26) g[i]=min(g[i],g[pos[j]]+1);
pos[ch[i]-'a'+1]=i;
int ans=inf;
fur(i,1,26)
if(f[1][i]==n+1)
printf("%c\n",i+'a'-1);
return 0;
ans=min(ans,g[f[1][i]]);
dfs(1,ans);
printf("\n");
return 0;
prb3:C
题目大意:给定\(n*m\)矩阵,求三点对三点共线的方案数
考试时式子推错,不想说什么了
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define int long long
const int xx=1e7+10;
const int n6=166666668;
const int mod=1e9+7;
int phi[xx],prime[xx],cnt=0,ans=0,m,n;
bool mark[xx];
inline void handle()
phi[1]=1;
fur(i,2,n)
if(!mark[i]) phi[i]=i-1,prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<=n;++j)
mark[i*prime[j]]=true;
if(i%prime[j]) phi[i*prime[j]]=phi[i]*(prime[j]-1);
else
phi[i*prime[j]]=phi[i]*prime[j];
break;
inline int calc(int x,int d,int u)return (x-u*d+x-d)*u/2%mod;
inline int C(int nm)return nm*(nm-1)%mod*(nm-2)%mod*n6%mod;
signed main()
scanf("%lld%lld",&n,&m);
if(n>m) swap(n,m);
--n;--m;
handle();
fur(i,1,n)
int tmp=phi[i];
tmp=(tmp*calc(n+1,i,n/i))%mod;
tmp=(tmp*calc(m+1,i,m/i))%mod;
ans=(ans+tmp)%mod;
ans=(ans-((n+1)*n/2%mod)*((m+1)*m/2%mod)%mod+mod)%mod;
ans=(ans<<1)%mod;
ans=(ans+(n+1)*C(m+1)%mod+(m+1)*C(n+1)%mod)%mod;
printf("%lld\n",ans);
return 0;
prob4:D
题目大意:给定\(n\)个标号结点所组成的任意图,求图中存在树的个数的\(k\)次方的和
知识储备:第二类斯特林数+prufer序列
而且上课心情不好,也没有认真听讲,导致这题不会,标程也没看懂,直接\(kuai\)学姐\(std\)算了。
(这压行真恶心):
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define LL long long
#define N 50005
using namespace std;
const int mo=998244353,G=3;
int n,K,rev[N*3],len,num,g[25][N];
LL S[25][25],jc[N],ny[N],wn[50],f[N*3],h[N*3],ans;
LL qp(LL x,LL y)
LL res=1;
for(;y;y>>=1ll,x=x*x%mo)
if(y&1ll) res=res*x%mo;
return res;
void pre()
jc[0]=ny[0]=1;
for(int i=1;i<=n;++i) jc[i]=jc[i-1]*i%mo;
ny[n]=qp(jc[n],mo-2);
for(int i=n-1;i>=0;--i) ny[i]=ny[i+1]*(i+1)%mo;
f[1]=1*ny[0];
for(int i=2;i<=n;++i) f[i]=qp(i,i-2)*ny[i-1]%mo;
S[0][0]=1;
for(int i=1;i<=K;++i)
for(int j=1;j<=i;++j)
S[i][j]=(S[i-1][j]*j%mo+S[i-1][j-1])%mo;
for(len=1,num=0;len<=n+n;len<<=1,num++);
for(int i=1;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(num-1));
for(int i=0;i<=45;++i) wn[i]=qp(G,(mo-1)/(1<<i));
void ntt(LL *x,int sign)
for(int i=0;i<len;++i) if(i<rev[i]) swap(x[i],x[rev[i]]);
for(int k=2,e=1;k<=len;k<<=1,e++)
for(int i=0;i<len;i+=k)
LL *a=x+i,*b=x+i+(k>>1); LL u,v,w=1;
for(int j=0;j<(k>>1);++j,w=w*wn[e]%mo)
u=a[j],v=b[j]*w%mo;
a[j]=u+v; a[j]>=mo?a[j]-=mo:0;
b[j]=u-v; b[j]<0?b[j]+=mo:0;
if(sign==-1)
int inv=qp(len,mo-2);
for(int i=0;i<len;++i) x[i]=x[i]*inv%mo;
reverse(x+1,x+len);
LL C(LL x,LL y) return x>=y?jc[x]*ny[y]%mo*ny[x-y]%mo:0;
int main()
scanf("%d%d",&n,&K);
pre();
g[0][0]=1; ntt(f,1);
for(int i=1;i<=K;++i)
memset(h,0,sizeof(h[0])*len);
for(int j=0;j<=n;++j) h[j]=1ll*g[i-1][j]*ny[j]%mo;
ntt(h,1);
for(int j=0;j<len;++j) h[j]=h[j]*f[j]%mo;
ntt(h,-1);
for(int j=1;j<=n;++j) g[i][j]=h[j]*jc[j-1]%mo;
for(int i=1;i<=n;++i)
LL tmp=qp(2,1ll*(n-i)*(n-i-1)/2ll)*C(n,i)%mo;
for(int j=1;j<=K;++j)
ans+=g[j][i]*S[K][j]%mo*jc[j]%mo*tmp%mo; //!!!!!
ans>=mo?ans-=mo:0;
printf("%lld\n",ans);
return 0;
以上是关于2019年7月26日(数学DP)的主要内容,如果未能解决你的问题,请参考以下文章