luogu P3403 跳楼机 同余最短路
LINK:跳楼机
很早之前就想学的一个东西。发现这个东西果然神奇。
我们要找到 所有的 w满足 \(w=1+ax+by+cz\).且 \(1\leq w\leq h\)
暴力枚举是不行的。
做法是这样的:先考虑 ax+by的情况 考虑先让x和y组合成一堆数字 然后最后加上一些z。
考虑对于一个楼层c 设res=c%z. 那么只要(ax+by)%z == res 找到这个最小的楼层那么之后所有 %z==res 的楼层都可以到达。
那么对于更多的ax+by的组合我们也只需要靠z到达即可。
考虑是否存在重复?不难发现因为同余的原因 每一个楼层最多只会在一个余数被计数。
考虑最小的楼层可以记录之后所有的楼层。
所以设\(f_i\)表示ax+by能跑到i层的最小楼层。
可以简单的发现 对于一个余数i来说 对答案的贡献为 \(\frac{(h-f_i)}{z}+1\)
其主要利用了固定两个参数 最后增加第三个参数 来计数。
可以证明 方案不重不漏.
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE ll i=p;i<=n;++i)
#define go(x) for(ll i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE ll i=n;i>=p;--i)
#define pii pair<ll,ll>
#define mk make_pair
#define RE register
#define S second
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define ull unsigned long long
#define mod 1000000007
#define ui unsigned
#define P 13331ll
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
register ll x=0,f=1;register char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const ll MAXN=100010;
ll n,ans,len;
ll x,y,z;
ll f[MAXN],vis[MAXN];
ll lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1];
priority_queue<pii>q;
inline void add(ll x,ll y,ll z)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
e[len]=z;
}
signed main()
{
//freopen("1.in","r",stdin);
get(n);get(x);get(y);get(z);
if(x==1||y==1||z==1){putl(n);return 0;}
memset(f,-1,sizeof(f));
f[1]=1;q.push(mk(1,1));
rep(0,z-1,i)add(i,(i+y)%z,y),add(i,(i+x)%z,x);
while(q.size())
{
ll x=q.top().S;q.pop();
if(vis[x])continue;
vis[x]=1;
go(x)
{
if(f[tn]==-1||f[tn]>f[x]+e[i])
{
f[tn]=f[x]+e[i];
q.push(mk(-f[tn],tn));
}
}
}
rep(0,z-1,i)if(f[i]!=-1&&n>=f[i])ans=(ans+(n-f[i])/z+1);
putl(ans);return 0;
}