首页 > 代码库 > 【BZOJ 2118】 2118: 墨墨的等式 (最短路)

【BZOJ 2118】 2118: 墨墨的等式 (最短路)

2118: 墨墨的等式

Description

墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N、{an}、以及B的取值范围,求出有多少B可以使等式存在非负整数解。

Input

输入的第一行包含3个正整数,分别表示N、BMin、BMax分别表示数列的长度、B的下界、B的上界。输入的第二行包含N个整数,即数列{an}的值。

Output

输出一个整数,表示有多少b可以使等式存在非负整数解。

Sample Input

2 5 10
3 5

Sample Output

5

HINT

对于100%的数据,N≤12,0≤ai≤5*10^5,1≤BMin≤BMax≤10^12。

Source

 

 

【分析】

  看了好久题解,感觉好机智啊。。

  题目可以理解成经典的背包问题。只是他问你的是[L,R]区间中有多少个容积是恰好可以装满的。

  然后这个范围很大啊,传统的暴力当然是行不通的了。

  考虑一个可以被拼出来的x,他里面可以包含ai也可以不包含ai。设x%ai=b(0<=b<ai)

  那么其实x+ai都可以被拼出来,显然。

  所以我们只要对于一个b,求出最小的可以拼出来的x,那么一直加ai也是可以的。

  直接把不同的b算出来的答案加起来就好了。

  要证明的话只要说明两个东西:

  1、不重复性,对于不同的可以拼出的x1,x2,如果他们%ai不同,那就不会算重复。

    如果他们%ai相同,也不会算重复【233我在搞笑?】

  2、不遗漏性,对于可以拼出来的x1,有一个模对应的b,那么肯定会算到嘛= =【233

  所以就这样搞笑的证明了??

  【想出来的人思路真的很妙【我根本看不出是最短路啊ORZ。。。

 

技术分享
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<vector>
 9 using namespace std;
10 #define LL long long
11 #define Maxm 7000100
12 #define Maxn 500010
13 #define INF 1000000000000LL
14 
15 int a[20];
16 
17 struct node
18 {
19     int x,y,next;
20     LL c;
21 }t[Maxm];int len=0;
22 
23 // vector<int > e[Maxn],c[Maxn];
24 
25 int first[Maxn];
26 
27 void ins(int x,int y,LL c)
28 {
29     t[++len].x=x;t[len].y=y;t[len].c=c;
30     t[len].next=first[x];first[x]=len;
31 }
32 
33 LL dis[Maxn];
34 bool inq[Maxn];
35 queue<int > q;
36 void spfa()
37 {
38     int st=0;
39     while(!q.empty()) q.pop();
40     memset(inq,0,sizeof(inq));
41     // memset(dis,63,sizeof(dis));
42     for(int i=0;i<a[1];i++) dis[i]=INF;
43     q.push(st);dis[st]=0;inq[st]=1;
44     while(!q.empty())
45     {
46         int x=q.front();
47         for(int i=first[x];i;i=t[i].next)
48         {
49             int y=t[i].y;
50         // for(int i=0;i<e[x].size();i++)
51         // {
52             // int y=e[x][i];
53             if(dis[y]>dis[x]+t[i].c)
54             {
55                 dis[y]=dis[x]+t[i].c;
56                 // dis[y]=dis[x]+c[x][i];
57                 while(!inq[y])
58                 {
59                     inq[y]=1;
60                     q.push(y);
61                 }
62             }
63         }
64         inq[x]=0;
65         q.pop();
66     }
67 }
68 
69 LL get_ans(LL x,LL y)
70 {
71     if(x<y) return 0;
72     return (x-y)/a[1]+1;
73 }
74 
75 int main()
76 {
77     int n;
78     LL L,R;
79     scanf("%d%lld%lld",&n,&L,&R);
80     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
81     sort(a+1,a+1+n);
82     memset(first,0,sizeof(first));
83     for(int i=1;i<=n;i++)
84      for(int j=0;j<a[1];j++)
85      {
86          ins(j,(j+a[i])%a[1],a[i]);
87      }
88     spfa();
89     LL ans=0;
90     for(int i=0;i<a[1];i++) 
91         ans+=get_ans(R,dis[i])-get_ans(L-1,dis[i]);
92     printf("%lld\n",ans);
93     return 0;
94 }
View Code

WA了很久竟然是spfa打错了。。。

 

2017-01-13 19:05:54

【BZOJ 2118】 2118: 墨墨的等式 (最短路)