P2371 [国家集训队] 墨墨的等式

传送门

\[\texttt\colorbox{lightgreen}{\color{green}passed}\;on\;2021.10.10 \]

\[\texttt\colorbox{darkblue}{\color{yellow}rewritten}\;on\;2021.10.15 \]


本来这一篇blog里已经上过这道题的代码了
但是想了想 还是觉得应该再写一篇(
写下思路以备不时之需


\[\mathbf{\huge\color{gold}{1 : 上 思 路}} \]

首先看题目上讲:

\[\sum_{i=1}^{n}a_ix_i=b \]

用辟谷冷静思考了一会……
这不就是\(\mathbf{\small{\color{gold}{跳楼机}}}\)加强版吗(

所以上同余最短路套路,区别是把一次建俩边换成用一个for来建边
并且在建完边之后sort一下来压空间复杂度

最后统计答案的时候要用上确界减掉下确界


\[left=max\{\frac{(dist[i]-i)}{a[1]},\frac{(l-i-1)}{a[1]}+1\} \]

这一句确定下确界,如果 \(dist[i]\) 在左端点 \(l\) 以下的话直接同步成 \(l\).
\(max\) 中第一个值不用+1的原因是下端点不一定取.

\[right=\frac{(r-i)}{a[1]} \]

这一句是上确界,求出对于 \([1,r]\) 的能取的 \(ans\).


\[\mathbf{\huge\color{gold}{2 : 上 代 码}} \]

#include <bits/stdc++.h>
#define MAXN 500005
#define int long long
using namespace std;

int n,l,r,cntr,ans,a[13],head[MAXN];
int dist[MAXN];
bool vis[MAXN];

struct edge
{
    int to,next,w;
}e[MAXN*10];

inline void add(int u,int v,int w)
{
    e[++cntr].to=v;
    e[cntr].w=w;
    e[cntr].next=head[u];
    head[u]=cntr;
}

inline void SPFA()
{
    queue<int> q;
    dist[0]=0;
    vis[0]=1;
    q.push(0);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to,w=e[i].w;
            if(dist[v]>dist[u]+w)
            {
                dist[v]=dist[u]+w;
                if(!vis[v])
                vis[v]=1,q.push(v);
            }
        }
    }
}

signed main()
{
    scanf("%lld %lld %lld",&n,&l,&r);
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        int input;
        scanf("%lld",&input);
        if(input) a[++cnt]=input;
        if(a[cnt]==1)
        {
            printf("%lld",r-l+1);
            return 0;
        }   
    }
    memset(dist,0x3f,sizeof(dist));
    sort(a+1,a+cnt+1);
    for(int i=0;i<a[1];i++)
        for(int j=2;j<=cnt;j++)
        add(i,(i+a[j])%a[1],a[j]);
    SPFA();
    int left,right;
    for(int i=0;i<a[1];i++)
    {
        if(dist[i]>r)
        continue;
        left=max((dist[i]-i)/a[1],(l-i-1)/a[1]+1);//下确界 
        right=(r-i)/a[1];
        ans+=right-left+1;
    }
    printf("%lld",ans);
    return 0;
}
上一篇:dijkstar算法求单源最短路径思路(图解)


下一篇:OpenGL 多线程共享纹理