题解 P2371 【[国家集训队]墨墨的等式】

· · 题解

这是一道数学?这是一个背包?不,这是一道图论!

观察发现系数都很小。我们根据POI2013SUMS的同余类bfs,首先转化为在同余最小的那个距离上搞,这样我们就可以找到第一个在%X(假定X是最小的那一个系数)最小的到达那个%X意义下的最小数。这样%X意义下更大的答案也一定可以到达。这样我们跑一下SPFA(显然这种题对SPFA十分友好),就可以找出来了,之后就随便搞出来了。

主要受到那道题启发才做出来。对于这样的一类题,有一个名字,叫同余类BFS,有机会学一学还是觉得十分机智的.

欢迎来Newuser蒟蒻博客看看!

talk is cheap , show me code!

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 500005;
ll dis[maxn];
int n;ll bmin,bmax;
int a[15]; bool rd[maxn];
queue<int>q;
void spfa() {
    for(int i=0;i<a[1];i++) dis[i]=1e15;
    q.push(0); rd[0]=1; dis[0]=0;
    while(q.size()) {
        int x=q.front(); q.pop(); rd[x]=0;
        for(int i=2;i<=n;i++) {
            int o = (x+a[i])%a[1];
            if(dis[o]>dis[x]+a[i]) {
                dis[o]=dis[x]+a[i];
                if(!rd[o]) {
                    q.push(o);  rd[o]=1;
                }
            }
        }
    } 
}
int main()  {
    scanf("%d%lld%lld",&n,&bmin,&bmax);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n);
    spfa();
    ll ans = 0;
    for(int i=0;i<a[1];i++) {
        if(dis[i]<=bmax) {
            if(dis[i]>=bmin) ans += ((bmax-dis[i])/a[1]+1);
            else {
                ans+=(bmax-dis[i])/a[1]+1;
                ans-=(bmin-dis[i]+a[1]-1)/a[1];
            }
        }
    }
    printf("%lld",ans);
}