[BZOJ 2118] 墨墨的等式

Link:

BZOJ 2118 传送门

Solution:

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

 

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

由$a\equiv 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:

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

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

 

posted @ 2018-06-05 15:36  NewErA  阅读(153)  评论(0编辑  收藏  举报