zoukankan      html  css  js  c++  java
  • BZOJ 2118 墨墨的等式(最短路)

    很开拓眼界的题。。

    题意:给出一个n元一次方程形如a1*x1+a2*x2...+an*xn=B,求满足解集为非负整数的B值在[L,R]范围内的种数。(n<=12,ai<=5e5,L<=R<=1e12)

    如果要求解集可以为负数,那么根据扩展欧几里得即可快速得到答案。

    现在的问题更像一个多重背包,但是L和R太大。

    首先可以把答案差分,变成求[0,R]和[0,L-1]。

    我们可以这样来考虑,如果我们找到B的一个任意解m,那么m+x1,m+2*x1,,,m+k*x1..这些显然也是解。

    而如果我们能找到B在模x1意义下所有的最小非负解,那么只需要把这些解加上若干个x1即可求得答案。

    现在我们的问题就变成了求一个B%x1=k的最小非负解。我们令g[i]表示B%x1=i的最小整数解。

    这是个最短路问题,首先有起点g[0]=0,而边就是加上的数字,比如加上一个x2,这就是一条0到x2%x1的边权为x2的边。

    这样跑一遍最短路,就求出了模x1意义下的最小非负解了。

    由于点的数量和x1有关,于是我们可以选择最小的xi来建图。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <bitset>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-8
    # define MOD 30031
    # define INF (LL)1<<60
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N=500005;
    //Code begin...
    
    struct Edge{int p, next, w;}edge[N*12];
    int head[N], cnt=1, a[N];
    LL dist[N];
    struct qnode{
        int v;
        LL c;
        qnode(int _v=0, LL _c=0):v(_v),c(_c){}
        bool operator<(const qnode &r)const{return c>r.c;}
    };
    bool vis[N];
    priority_queue<qnode>que;
    void add_edge(int u, int v, int w){
        edge[cnt].p=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++;
    }
    void Dijkstra(int n, int start){
        mem(vis,false);
        FO(i,0,n) dist[i]=INF;
        priority_queue<qnode>que;
        dist[start]=0; que.push(qnode(start,0)); qnode tmp;
        while (!que.empty()) {
            tmp=que.top(); que.pop();
            int u=tmp.v;
            if (vis[u]) continue;
            vis[u]=true;
            for (int i=head[u]; i; i=edge[i].next) {
                int v=edge[i].p, cost=edge[i].w;
                if (!vis[v]&&dist[v]>dist[u]+cost) dist[v]=dist[u]+cost, que.push(qnode(v,dist[v]));
            }
        }
    }
    int main ()
    {
        int n;
        LL ans=0, L, R;
        scanf("%d%lld%lld",&n,&L,&R);
        FOR(i,1,n) scanf("%d",a+i);
        sort(a+1,a+n+1);
        int pos=0;
        FOR(i,1,n) if (a[i]) a[++pos]=a[i];
        if (pos==0) {puts("0"); return 0;}
        FO(i,0,a[1]) FOR(j,2,pos) {int x=i+a[j]; add_edge(i,x%a[1],x/a[1]);}
        Dijkstra(a[1],0);
        FO(i,0,a[1]) {
            LL x=dist[i]*a[1]+i;
            if (x<=R) ans+=(R-x)/a[1]+1;
            if (x<=L-1) ans-=(L-1-x)/a[1]+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    为什么 PCB 生产时推荐出 Gerber 给工厂?
    Fedora Redhat Centos 有什么区别和关系?
    【KiCad】 如何给元件给元件的管脚加上划线?
    MCU ADC 进入 PD 模式后出现错误的值?
    FastAdmin 生产环境升级注意
    EMC EMI 自行评估记录
    如何让你的 KiCad 在缩放时不眩晕?
    KiCad 5.1.0 正式版终于发布
    一次单片机 SFR 页引发的“事故”
    java基础之集合
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6889159.html
Copyright © 2011-2022 走看看