同余最短路
- 给定个整数,可以重复取,能拼凑出多少个其他整数
- 给定个整数,不能拼凑出的最小(最大)整数
- 至少要多少个数才能拼出模余的数
给定个整数,可以重复取,能拼凑出多少个其他整数
给定对于有多少个满足
选取,假设
那么加边add(i,(i+y)%x,y),add(i,(i+z)%x,x)
那么找到了模下的最小整数解,对于任意的答案,也能做到,因此求
cpp
void solve(){
int h,x,y,z;
cin>>h>>x>>y>>z;
h--;//h-1,从0开始
if(y<x)swap(x,y);
if(z<x)swap(x,z);
vector<int> dis(x,LLONG_MAX);
priority_queue<PII,vector<PII>,greater<>> pq;
pq.push({0,0});
dis[0]=0;
while(!pq.empty()){
auto [d,u]=pq.top();
pq.pop();
if(d>dis[u])continue;
for(auto val:{y,z}){
int v=(u+val)%x;
if(dis[v]>d+val){
dis[v]=d+val;
pq.push({dis[v],v});
}
}
}
int ans=0;
for(int i=0;i<x;i++){
if(dis[i]<=h)ans+=(h-dis[i])/x+1;
}
cout<<ans<<"\n";
}
给定个整数,不能拼凑出的最大整数
记A序列最小值为
答案是
- 特判:如果存在,那么任意数都能被表达;如果gcd>1,那么有无限个不能被表达的数,不存在最大值
cpp
void solve(){
int n,m;
cin>>n>>m;
vector<int> a;
for(int i=1;i<=n;i++){
int x;
cin>>x;
for(int j=0;j<=m&&x-j>=1;j++)a.push_back(x-j);
}
int g=0;
for(auto x:a){
if(x==1){
cout<<"-1\n";
return;
}
g=__gcd(g,x);
}
if(g>1){
cout<<"-1\n";
return;
}
ranges::sort(a);
vector<int> dis(a[0],INF);
priority_queue<PII,vector<PII>,greater<PII>> pq;
pq.push({0,a[0]});
dis[0]=0;
while(!pq.empty()){
auto [d,u]=pq.top();
pq.pop();
if(d>dis[u])continue;
for(int i=1;i<a.size();i++){
int v=(u+a[i])%a[0];
if(dis[v]>d+a[i]){
dis[v]=d+a[i];
pq.push({dis[v],v});
}
}
}
int ans=-1;
for(int i=0;i<a[0];i++)ans=max(ans,dis[i]-a[0]);
cout<<ans<<"\n";
}背包问题,容量
假设基准值为,一个物品为,那么只会存在个环,转两圈的方法就可以更新所有答案
选择单位体积价值最大的作为基准点
就是答案
复杂度为
cpp
void solve(){
int n,q;
cin>>n>>q;
vector<int> v(n+1),c(n+1);// 容量,价值
int m=-1,w=-1;
for(int i=1;i<=n;i++){
cin>>v[i]>>c[i];
if(m==-1||w*v[i]<c[i]*m){
m=v[i];
w=c[i];
}
}
vector<int> dp(m,-INF);
dp[0]=0;
for(int i=1;i<=n;i++){
for(int j=0,lim=__gcd(v[i],m);j<lim;j++){
for(int p=j,_=0;_<2;_+=p==j){
if(dp[p]!=-INF)dp[(p+v[i])%m]=max(dp[(p+v[i])%m],dp[p]+c[i]-(p+v[i])/m*w);
p=(p+v[i])%m;
}
}
}
while(q--){
int V;
cin>>V;
int x=V%m;
if(dp[x]==-INF) cout<<"-1\n";
else cout<<dp[x]+V/m*w<<"\n";
}
}