D
bfs
每次可以给当前数字乘a,或者把最后一位移动到第一位(前提是最后一位不为0).问能不能把1变成n?能的话求最少操作次数
对于一个分支不确定能不能走到头,也不确定深度的问题,还是求最小代价的话,显然不能dfs,应该bfs。
需要注意的是记忆化,用数组就可以,大小开到n∗10n*10n∗10即可,然后还需要判断乘a后会不会越界
void solve(){
int a,n;
cin>>a>>n;
queue<int>q;
vi d(n*11,1e18);
d[1]=0;
q.push(1);
while(q.size()){
int x=q.front();
q.pop();
// cout<<x<<'\n';
if(x==n)break;
if(x*a<n*10){
if(d[x*a]>d[x]+1){
d[x*a]=d[x]+1;
q.push(x*a);
}
}
string s=to_string(x);
if(s.back()=='0')continue;
char c=s.back();
s.pop_back();
s=c+s;
int y=stoi(s);
if(y>=10*n)continue;
if(d[y]>d[x]+1){
d[y]=d[x]+1;
q.push(y);
}
}
if(d[n]<1e18){
cout<<d[n];
}
else{
cout<<-1;
}
}
E
离线 最小生成树
给一个图,给一堆额外的边,问每条边如果加入这张图,会不会在最小生成树中
把询问的边也加入边集里,然后跑最小生成树,访问到询问的边时,只记录是否要加入最小生成树,并不真的加入。
int f[N];
int find(int x){
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
void solve(){
int n,m,q;
cin>>n>>m>>q;
vvi e;
rep(i,1,m){
int u,v,w;
cin>>u>>v>>w;
e.push_back({w,u,v,0});
}
rep(i,1,q){
int u,v,w;
cin>>u>>v>>w;
e.push_back({w,u,v,i});
}
rep(i,1,n){
f[i]=i;
}
sort(e.begin(),e.end());
vi ans(q+1);
for(auto &t:e){
int w=t[0],u=t[1],v=t[2],id=t[3];
u=find(u),v=find(v);
if(id){
if(u!=v){
ans[id]=1;
}
}
else{
f[u]=v;
}
}
rep(i,1,q){
if(ans[i]){
cout<<"Yes\n";
}
else{
cout<<"No\n";
}
}
}
F
数位dp变形,求合法数字和
求包含所有给定数位的,不超过n的所有数字之和。首先如果求数字个数很简单,参数里增加一个mask记录当前已有的数位即可
求和的话,我们在枚举当前位填什么数字时,考虑这一位的数字的贡献,也就是考虑它出现在从低往高的第几位,以及出现多少次。
第几位可以通过当前dp到第几位算出来,预处理一下10的幂即可;出现多少次就是看往后dp的方案数,直接利用求合法数字个数的dp的结果即可。
所以我们让dp返回两个值,一个是后面的合法数字个数,一个是后面的合法数字之和。每一层计算合法数字之和时,除了计算当前放的数字的贡献,还要累加后面的和
复杂度不要看数字很大就害怕,观察dp数组的状态数,以及每一层dfs里面的复杂度,其实只有O(nm2m)O(nm2^m)O(nm2m)
int f[N][1<<10][2][2],g[N][1<<10][2][2];
void solve(){
string n;
int m;
cin>>n>>m;
vi c(m+1);
rep(i,1,m){
cin>>c[i];
}
int len=n.size();
vi pw(len+1);
pw[0]=1;
rep(i,1,len){
pw[i]=pw[i-1]*10%M2;
}
memset(f,-1,sizeof f);
memset(g,-1,sizeof g);
auto &&dfs=[&](auto &&dfs,int i,int mask,int lim,int lead)->pii{
if(i==len){
rep(j,1,m){
if((mask>>c[j]&1)==0){
return {0,0};
}
}
return {1,0};
}
if(f[i][mask][lim][lead]!=-1){
return {f[i][mask][lim][lead],g[i][mask][lim][lead]};
}
int up;
if(lim)up=n[i]-'0';
else up=9;
int cnt=0,sum=0;
rep(d,0,up){
pii res;
if(lead){
if(d==0){
res=dfs(dfs,i+1,mask,lim&&d==up,1);
}
else{
res=dfs(dfs,i+1,mask|(1<<d),lim&&d==up,0);
}
}
else{
res=dfs(dfs,i+1,mask|(1<<d),lim&&d==up,0);
}
cnt+=res.fi;
sum+=res.se+d*res.fi%M2*pw[len-i-1]%M2;
cnt%=M2;
sum%=M2;
}
return {f[i][mask][lim][lead]=cnt,g[i][mask][lim][lead]=sum};
};
pii res=dfs(dfs,0,0,1,1);
cout<<res.se;
}