zoukankan      html  css  js  c++  java
  • [bzoj2118]墨墨的等式——同余最短路

    题目大意:

    墨墨突然对等式很感兴趣,他正在研究(a_1x_1+a_2x_2+…+a_nx_n=B)存在非负整数解的条件
    他要求你编写一个程序,给定(N,{a_n})以及(B)的取值范围,求出有多少B可以使等式存在非负整数解。
    (Nleq12,0leq a_ileq 5 imes 10^5,1leq B_{min} leq B_{max} leq 10^{12})

    思路:

    题目中要求的是非负整数解,于是我们可以把每一个数看成一个物品,求所有物品可以组成的体积。
    但是直接跑背包显然是接受不了的
    考虑到最后的体积集合,我们把它按照a[1](也就是任意一个数)的剩余类分类。
    虽然可以组成的体积种类很多,但是按照剩余类分类之后体积的种类就只有5e5种 于是我们只需要求出每一个剩余类最小的体积就好了,每一个合法的体积一定可以表示成(a[1] imes x+b)
    建图其实也很简单。
    每一个余数代表一个点,点u可以向点((v+a[j])mod a[1])连一条权值为a[j]的边。
    从0开始单源最短路即可以得到所有余数的最小体积。

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define debug(x) cout<<#x<<"="<<x<<endl
    #define pii pair<ll,int>
    #define fi first
    #define se second
    #define mk make_pair
    typedef long long ll;
    
    using namespace std;
    
    void File(){
        freopen("bzoj2118.in","r",stdin);
        freopen("bzoj2118.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
        T __=0,mul=1; char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')mul=-1;
            ch=getchar();
        }
        while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
        _=__*mul;
    }
    
    const int maxn=20;
    const int maxm=5e5+10;
    const int maxe=6e6+10;
    int n,a[maxn];
    ll b0,b1,ans,w[maxe],dis[maxm];
    int beg[maxm],to[maxe],las[maxe],cnte=1;
    
    void add(int u,int v,ll val){las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; w[cnte]=val;}
    
    void init(){
        read(n); read(b0); read(b1);
        REP(i,1,n)read(a[i]);
        REP(i,0,a[1]-1)REP(j,1,n)
            add(i,(i+a[j])%a[1],a[j]);
    }
    
    priority_queue< pii,vector<pii>,greater<pii> >qu;
    void Dijkstra(){
        memset(dis,63,sizeof(dis));
        dis[0]=0; qu.push(mk(0,0));
        while(!qu.empty()){
            ll d=qu.top().fi; int u=qu.top().se;
            qu.pop();
            if(dis[u]!=d)continue;
            for(int i=beg[u];i;i=las[i]){
                int v=to[i];
                if(d+w[i]<dis[v]){
                    dis[v]=d+w[i];
                    qu.push(mk(dis[v],v));
                }
            }
        }
    }
    
    void work(){
        REP(i,0,a[1]-1){
            ll val=dis[i];
            if(val<b0)ans+=(b1-val)/a[1]-(b0-val-1)/a[1];
            else if(val<=b1)ans+=(b1-val)/a[1]+1;
        }
        printf("%lld
    ",ans);
    }
    
    int main(){
    //	File();
        init();
        Dijkstra();
        work();
        return 0;
    }
    
  • 相关阅读:
    期中架构实现步骤
    安装centos以及优化步骤
    inotify+rsync实现实时热备
    [转]ubuntu安装vncserver实现图形化访问
    [转]电烙铁的使用小技巧
    彻底解决 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    解读系统托盘图标隐藏(删除)
    一个小公式帮你轻松将IP地址从10进制转到2进制
    [查阅]Dalvik opcodes
    [查阅]MSIL Instruction Set
  • 原文地址:https://www.cnblogs.com/ylsoi/p/9861067.html
Copyright © 2011-2022 走看看