网络赛的时候没有搞出来,前几天做Atcoder的时候做到了一场STL场的比赛,就回来一起把这个题也补了。
题解:
首先肯定的是,如果当前的
x
x
x合法,一定可以在序列中找到一个
a
[
i
]
a[i]
a[i],满足:
x
≡
a
[
i
]
m
o
d
d
x \equiv a[i] \enspace mod \enspace d
x≡a[i]modd,其中
d
d
d为
a
[
i
]
a[i]
a[i]的总和。
并且我们发现,当
d
<
0
d < 0
d<0时,我们可以把
a
[
i
]
a[i]
a[i]和
x
x
x全部取反,这样再讨论其实和正数的情况是一致的。
所以我们的思路综述:
- d = 0 d = 0 d=0:直接在序列中查找有没有 x = a [ i ] x = a[i] x=a[i]存在。
- d > 0 d > 0 d>0:找到满足 x ≡ a [ i ] m o d d x \equiv a[i] \enspace mod \enspace d x≡a[i]modd的 a [ i ] a[i] a[i],如果存在多个,则找到距离 x x x最近且小于它的数。
- d < 0 d < 0 d<0:把 x x x和 a [ i ] a[i] a[i]全部取反,这样就又回到了第二种情况。
如何设计算法解决
d
>
0
d > 0
d>0的问题?
map
套vector
套pair
就行
我们把和
x
x
x同余的每一种情况建立一个map<int, vector<?> >
,同时,我们的vector
里希望存放的信息有:
a
[
i
]
a[i]
a[i]和
i
i
i,那就可以建立一个pair
,于是最后我们就可以建立出map<int, vector<pair<int, int> > >
。
然后对每一个vector
进行排序,对于输入的每一个
x
x
x,找到对应的
x
m
o
d
d
x \enspace mod \enspace d
xmodd,在这一维度的vector
中查找满足条件的
a
[
i
]
,
i
a[i],i
a[i],i。
最后的答案显然是
i
+
(
x
−
a
[
i
]
)
d
∗
n
i + \frac{(x - a[i])}{d} * n
i+d(x−a[i])∗n。
//This code is written by Kyrie Qi
//QQ : 601383880
//Email : cuc_qzl@cuc.edu.cn
#include <bits/stdc++.h>
#define fi first
#define se second
#define ill __int128
#define ll long long
#define pb push_back
#define mkp make_pair
#define lson(x) x << 1
#define lowbit(x) (x & -x)
#define PII pair <ll, ll>
#define rson(x) (x << 1 | 1)
#define ull unsigned long long
#define me(a,b) memset (a, b, sizeof(a))
#define ios std :: ios :: sync_with_stdio(false)
#define debug(x) cout << #x << " = " << x << endl
const double Exp = 1e-9;
const int INF = 0x3f3f3f3f;
const int inf = -0x3f3f3f3f;
const int mode = 1000000007;
const double pi = acos(-1.0);
using namespace std;
const int maxn = 1e5 + 10;
int t, n, m;
ll a[maxn], x, sum[maxn];
map<ll, vector<PII>> mp;
map<ll, int> ma;
int main()
{
scanf ("%d", &t);
while (t -- ) {
mp.clear();
ma.clear();
me (sum, 0ll);
scanf ("%d%d", &n, &m);
for (int i = 1;i <= n;i ++) {
scanf ("%lld", &a[i]);
sum[i] = a[i] + sum[i - 1];
}
if (sum[n] == 0ll) {
for (int i = 1;i <= n;i ++) if (!ma[sum[i]]) ma[sum[i]] = i;
for (int i = 1;i <= m;i ++) {
scanf ("%lld", &x);
if (x == 0) printf ("0\n");
else if (ma[x]) printf ("%d\n", ma[x]);
else printf ("-1\n");
}
}
else {
bool f = 0;
if (sum[n] < 0) {
f = 1;
for (int i = 1;i <= n;i ++) sum[i] = -sum[i];
}
for (int i = 1;i <= n;i ++) {
int d = (sum[i] % sum[n] + sum[n]) % sum[n];
mp[d].push_back(mkp(-sum[i], i)); //注意这里很贼的方法,省去了自定义排序。
}
for (auto it = mp.begin();it != mp.end();it ++) sort (it->second.begin(), it->second.end()); //sum从大到小,i从小到大。
for (int i = 1;i <= m;i ++) {
scanf ("%lld", &x);
if (f) x = -x;
if (x == 0) {
printf ("0\n");
continue;
}
int d = (x % sum[n] + sum[n]) % sum[n];
if (mp[d].empty()) {
printf ("-1\n");
continue;
}
else {
PII tmp = {-x, 0};
int p = lower_bound(mp[d].begin(), mp[d].end(), tmp) - mp[d].begin();
if (p == mp[d].size()) printf ("-1\n");
else {
ll ans = mp[d][p].second;
ans += (x + mp[d][p].first) / sum[n] * n;
printf ("%lld\n", ans);
}
}
}
}
}
return 0;
}