[BZOJ 2118] 墨墨的等式

Link:

BZOJ 2118 传送门

Solution:

一眼望过去是数论题,结果是最短路经典模型???

从一个很基础的性质出发:

由$aequiv b(mod c)$,得$(a+c*k)equiv b(mod c)$

设$a[1]$为$<a_n>$中的最小值,$dist[i]$为$mod a[1]=i$的最小数

因为如果$X$合法,则$X+a[1]*k$一定合法

因此我们只要找到由$<a_n>$组成,$mod a[1]$分别为$0,1,2......a[1]-1$的最小的数,

就等于找到了${<a_n>}$能构成数的集合(选择$a[1]$是为了保证余数数量尽可能少)

这样,我们只要计算对于每个$i$,有多少个$dist[i]+k*a[1]$在$[L,R]$内即可

而求解$dist[i]$就可以交给最短路算法了(建边$<i,(i+a[j])mod a[1],a[j]>$)

Code:

//by NewErA
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int,int> P;

const int MAXN=5e5+5;
ll dat[MAXN],n,L,R,dist[MAXN];
vector<P> G[MAXN];

void dijkastra()
{
    priority_queue<P,vector<P>,greater<P> > Q;
    for(int i=0;i<MAXN;i++) dist[i]=(ll)1e60;dist[0]=0;
    Q.push(P(0,0));
    
    while(!Q.empty())
    {
        int t=Q.top().second;Q.pop();
        for(int i=0;i<G[t].size();i++)
        {
            int v=G[t][i].first;
            if(dist[v]>dist[t]+G[t][i].second) 
                dist[v]=dist[t]+G[t][i].second,Q.push(P(dist[v],v));
        }
    }
}

int main()
{
    cin >> n >> L >> R;
    for(int i=1;i<=n;i++) cin >> dat[i];
    sort(dat+1,dat+n+1);
    
    for(int i=0;i<dat[1];i++) //计算dist
        for(int j=2;j<=n;j++)
            G[i].push_back(P((i+dat[j])%dat[1],dat[j]));
    dijkastra();
    
    ll res=0;
    for(int i=0;i<dat[1];i++)  //统计答案
    {
        if(dist[i]<=R)
        {
            ll l=max((ll)0,(L-dist[i])/dat[1]);
            if(l*dat[1]+dist[i]<L) l++;
            ll r=(R-dist[i])/dat[1];
            if(r*dat[1]+dist[i]>R) r--;
            res+=(r-l+1);
        }
    }
    cout << res;
    return 0;
}

Review:

这里的同余思想值得借鉴,

如果能找到符合条件的模式,可通过同余的方式来简化方案数(变为余数个数)

原文地址:https://www.cnblogs.com/newera/p/9140072.html