zoukankan      html  css  js  c++  java
  • 【BZOJ2118】墨墨的等式

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2118


    好巧妙的一道题!第一眼看感觉是一道数论题,而且和小凯的疑惑还有些相似之处,其实人家是一道图论题。。。

    看别人写的博客都比较涩,我也是看了好多,想了好久才明白,所以,下面我尽量好好写,让人更好理解。

    题目大意是问,在一段区间里,有多少个数B可以使a1x1+a2x2+...+anxn=B有解。

    我们知道,对于这n个a,k*a+c可以表示所有非负整数,k和c均为非负整数且0<=c<a。所以我们不如让a取n个a中最小的。

    假设我们已求得k*a+c可以使上述方程有解,那么显然(k+1)*a+c也可以,所以只要求出最小的k*a+c就可以了。

    其实相当于用若干个a1、a2、...、an凑k*a+c,a是不需要凑的,关键是c,我们关心能不能凑出一个最小的数使之%a=c。

    当c=0一定是可以的,而且这个数就是0,那么给0加上任意一个a,就可以凑出另一个c了(现在的a!=最小的a),但是需要加上那个a,也就是会有代价,因为我们想要最小的那个数。

    我们发现这不就是最短路问题吗?一共有0到a-1共a个点(因为是在%a意义下),每个点向外有些边指向另外的点,这些边还有权值,我们想知道从起点0到其他点过程中经过边最小权值之和。

    所以,对于0到a-1每个点i,建一条从i指向(i+a[j])%a,权值为a[j]的边,跑一遍最短路就可以求出%a=c的最小的数。当然a[j]是指上述n个a的每一个,为了避免有自环,最小的a跳过就好了。

    求出来以后,我们对他+a进行调整,在要求的范围内的计数即可,不过统计答案这里还是需要处理细节的,如果你选择了一种比较快的方法。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <queue>
     5 
     6 using namespace std;
     7 
     8 typedef long long ll;
     9 
    10 const int maxn = 15, maxp = 5e5 + 5;
    11 ll inf = 1e12 + 5;
    12 
    13 int n, a[maxn], p = maxp;
    14 
    15 int head[maxp], eid;
    16 
    17 struct Edge {
    18     int v, w, next;
    19 } edge[maxp * maxn];
    20 
    21 inline void insert(int u, int v, int w) {
    22     edge[++eid].v = v;
    23     edge[eid].w = w;
    24     edge[eid].next = head[u];
    25     head[u] = eid;
    26 }
    27 
    28 int vis[maxp];
    29 ll dist[maxp];
    30 
    31 struct node {
    32     int id, dist;
    33     node(int i, int d) : id(i), dist(d) {}
    34     bool operator < (const node& rhs) const {
    35         return dist > rhs.dist;
    36     }
    37 };
    38 
    39 priority_queue<node> q;
    40 
    41 inline void dijkstra() {
    42     memset(dist, inf, sizeof(dist));
    43     dist[0] = 0;
    44     q.push(node(0, 0));
    45     while (!q.empty()) {
    46         int u = q.top().id;
    47         q.pop();
    48         if (vis[u]) continue;
    49         vis[u] = 1;
    50         for (int p = head[u]; p; p = edge[p].next) {
    51             int v = edge[p].v, w = edge[p].w;
    52             if (dist[v] > dist[u] + w) {
    53                 dist[v] = dist[u] + w;
    54                 q.push(node(v, dist[v]));
    55             }
    56         }
    57     }
    58 }
    59 
    60 int main() {
    61     ll bmin, bmax, ans = 0;
    62     scanf("%d%lld%lld", &n, &bmin, &bmax);
    63     for (int i = 1; i <= n; ++i) {
    64         scanf("%d", &a[i]);
    65         p = min(p, a[i]);
    66     }
    67     for (int i = 0; i < p; ++i)
    68         for (int j = 1; j <= n; ++j) {
    69             if (a[j] == p) continue; //避免有自环
    70             insert(i, (i + a[j]) % p, a[j]);
    71         }
    72     dijkstra();
    73     for (int i = 0; i < p; ++i) {
    74         if (dist[i] > bmax) continue;
    75         ll l = max(0LL, (bmin - dist[i]) / p);
    76         ll r = (bmax - dist[i]) / p;
    77         if (l * p + dist[i] < bmin) ++l;
    78         ans += r - l + 1;
    79     }
    80     printf("%lld", ans);
    81     return 0;
    82 }
    AC代码
  • 相关阅读:
    01 WEB白帽子Python入门
    07 SSRF漏洞
    JAVA基础学习day04--IDEA、方法
    一些常用的计算机快捷指令
    记录一次xss平台的安装
    upload-labs
    蓝队防护基础
    bagecms的代码审计
    window入侵排查基本
    常用端口总结
  • 原文地址:https://www.cnblogs.com/Mr94Kevin/p/9902245.html
Copyright © 2011-2022 走看看