Problem DescriptionThere's a very popular game called jump a jump recently
.In order to get good marks, many people spend a lot of time in this game.Wei is the master of jump a jump,he can easily get a very high score every time.Recently he discovered that because of his muscle memory,he could not fully control his game score.
Now he wants you to help him figure out the nearest score that he can get from his desired score. Every time he jumps, he chooses one from m distances,he can jump until he wants to end,and he can also use every distance any times.
InputInput contains multiple test cases.
For each test case,the first line has a number n(n <= 1e15) to indicate the score he desired.The next line has a number m(m <= 2000), which indicates how many choices each step has.
The last line has m integers bi(1<=bi <= 5000) representing the ith distances.
Output For each test case,output is the absolute value of the difference between the nearest score he can get
and his desired score.
题意大概就是给一个n维向量X(xi>=0),让你求一个向量Y(yi>=0),使得X和Y的点积最接近一个给定的数n,本质还是取模最短路,可以取b1为模数跑最短路,设d[x]为模b1为x的步数中的最小值,那么显然d[x]+k*b1都可以被表示出来,所以求出d[x]后扫一遍就可以得到最接近n的值了. 因为时间仓促所以数据造的水了一点,导致几个错误做法水了过去.
#include
#define N 50005
#define MOD 1000000007
using namespace std;
typedef long long ll;
typedef pair pii;
ll n,m,x,ans,d[N],b[N];
bool done[N];
priority_queue< pii,vector,greater > q;
int main()
{
cin.sync_with_stdio(false);
while(cin>>n>>m)
{
ans = 1e16;
for(int i = 1;i <= m;i++) cin>>b[i];
sort(b+1,b+1+m);
memset(d,0x3f,sizeof(d));
memset(done,0,sizeof(done));
d[0] = 0;
q.push(make_pair(d[0],0));
while(!q.empty())
{
int u = q.top().second;
q.pop();
if(done[u]) continue;
done[u] = true;
for(int i = 1;i <= m;i++)
if(d[(b[i]+u) % b[1]] > d[u] + b[i])
{
d[(b[i]+u) % b[1]] = d[u] + b[i];
q.push(make_pair(d[(b[i]+u) % b[1]],(b[i]+u) % b[1]));
}
}
ll target = n % b[1];
for(int i = 0;i < b[1];i++)
{
if(d[i] > n)
{
ans = (d[i]-n) < ans ? d[i]-n : ans;
continue;
}
ll Max = max(target,i*1ll),Min = min(target,i*1ll);
ans = min(ans,min(Max-Min,b[1]-Max+Min));
}
cout<