传送门: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 1e9
using 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也没发现,,