bzoj 2118: 墨墨的等式

来源:互联网 发布:美国历史人物 知乎 编辑:程序博客网 时间:2024/04/30 06:27

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2118
思路:这是一道经典问题,所以虽然不是自己想出来的还是在博客里写一下,练习了堆优化dijistra,观察,可以发现变量个数和系数范围还是比较小的,然而解的个数和规模确大到无法处理,这类问题,,,是有通法的,,,考虑,如何将解归类,也就是根据特征划分为若干集合,按集合整体快速计算,集合个数要小,单个集合计算要快O(1)或O(logn)都是可以的,也就是将解空间单射到另一个空间,往往题目中有一些数据达到了10^7以上,不看他,我们就看那些10^6以下的较小的数据,以本题为例子:发现系数很小,那么我们进行归类,每一个解都能唯一的表示为x = p*q + r的形式,也就是说形成单射,这提示我们根据余数分类,考虑,我们如果选取某个模数为p,余数为r,那么如果
x可以被如此表示,那么x + j*p都是可以的,然而我们要找最小的满足条件的x,怎么办呢,,而且是要找很多很多x,,数论走不通?图论建模,最短路模型非常简单,直接搞好了,,,
同类题目:dzy loves math 2
(未完待续)
代码:

#include<iostream>#include<cstring>#include<string>#include<cstdio>#include<algorithm>#define N 12#define M 500000#define inf 1e9using namespace std;typedef long long LL;struct edge{ int nxt,point,v; LL w;};struct data{ LL value; int id;};edge e[((N*M)<<1)+5];data heap[M+5];LL a[N+5],dis[M + 5],cnt,n,Bmin,Bmax,mini,minist;void addedge(int u1,int v1,LL w1){     e[++cnt].nxt = e[u1].point; e[u1].point = cnt; e[cnt].v = v1; e[cnt].w = w1;}//void insert(int u1,int v1){ addedge(u1,v1); addedge(v1,u1);}inline LL getnum(){    char c; LL num;    while (!isdigit(c = getchar()));    num = c - '0';    while (isdigit(c = getchar())) num = 10 * num + c - '0';    return num;}void init(){    n = getnum(); Bmin = getnum(); Bmax = getnum(); cnt = 0;    for (int i = 1;i <= n; ++i) a[i] = getnum();    sort(a + 1,a + n + 1);    mini = a[1];}void make_it(){    for (int i = 0;i < mini; ++i)      for (int j = 1;j <= n; ++j)        addedge(i,(i + a[j])%mini,a[j]);}inline void push(data x){    heap[++cnt] = x;    int j = cnt;    while (j>1&&heap[j].value < heap[(j>>1)].value) swap(heap[j],heap[j>>1]);}inline data pop(){    data x = heap[1];    heap[1] = heap[cnt--];    int j = 1;    while (1){        minist = j;        if ((j<<1)<=cnt) minist = j<<1;        if ((j<<1|1)<=cnt&&heap[minist].value > heap[(j<<1|1)].value) minist = j<<1|1;        if (minist == j) break;        swap(heap[j],heap[minist]);        j = minist;     }    return x;}void heap_dijistra(){    data tmp = (data) {0,0}; cnt = 0;    memset(dis,0x7f,sizeof(dis));    dis[0] = 0; push(tmp);     while (cnt){         data x = pop();          //cout<<x.id<<" "<<x.value<<endl;         for (int p = e[x.id].point;p ; p = e[p].nxt)           if (dis[e[p].v] > dis[x.id] + e[p].w){                dis[e[p].v] = dis[x.id] + e[p].w;                push((data){dis[e[p].v],e[p].v});           }    }}inline LL query(LL maxi){    if (maxi == 0) return 1;    if (maxi < 0) return 0;    LL sum = 0;     for (int i = 0;i < mini; ++i)      if (dis[i] <= maxi)        sum += (maxi - dis[i])/mini + 1;    return sum;}void DO_IT(){    make_it();    heap_dijistra();    //cout<<query(10)<<endl;    //cout<<query(4);    cout<<query(Bmax) - query(Bmin - 1);}int main(){    init();    DO_IT();    return 0;}总结:快速读入和数据该longlong就longlong,爆了很久int也没发现,,
0 0