http://acm.hdu.edu.cn/showproblem.php?pid=7130
第一步先求出前缀和和总和。
判断sum值在不同情况下的处理情况。
当sum==0,所有的数据只会在第一轮中出现一次。即若不在第一次中出现就不会出现。
当sum<0时,将前缀和全部反转,并标记已翻转。
将前缀和存入对应的取模后的map中进行存储,按照前缀和大小进行排序。然后二分查找若能找不到对应的取模值则输出-1,找到对应取模值后将前缀和值在数组中的位置取出。若取出值为最后,即为找不到对应值(只是对应的取模值相同)。找到后将在第几轮中乘以n加上前缀和的序号即为最后值。
#include<iostream>
#include<map>
#include<vector>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define ll long long
ll a[200005],pre[200005];
map<ll,int > vs;
map<ll,vector<pair<ll,int>>> shu;
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
int flag=0;
ll sum=0;
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
pre[i]=pre[i-1]+a[i];
sum+=a[i];
}
if(sum<0)
{
sum=-sum;
flag=1;
for(int i=1; i<=n; i++)
pre[i]=-pre[i];
}
if(sum==0)
{
vs.clear();
for(int i=1; i<=n; i++)
if(vs.find(pre[i])==vs.end())
{
vs[pre[i]]=i;
}
while(m--)
{
ll x;
scanf("%lld",&x);
if(x==0)
{
cout<<0<<endl;
continue;
}
if(vs.find(x)==vs.end())
cout<<-1<<endl;
else
cout<<vs[x]<<endl;
}
continue;
}
shu.clear();
for(int i=1; i<=n; i++)
{
ll res=(pre[i]%sum+sum)%sum;
shu[res].push_back({-pre[i],i});
}
for(auto it=shu.begin(); it!=shu.end(); it++)
{
sort(it->second.begin(),it->second.end());
}
while(m--)
{
ll x;
cin>>x;
if(flag==1)
x=-x;
if(x==0)
{
cout<<0<<endl;
continue;
}
ll xr=(x%sum+sum)%sum;
if(shu.find(xr)==shu.end())
{
cout<<-1<<endl;
continue;
}
pair<ll,int> ask= {-x,0};
int pos=lower_bound(begin(shu[xr]),end(shu[xr]),ask)-shu[xr].begin();
if(pos==shu[xr].size())
cout<<-1<<endl;
else
{
ll ans=shu[xr][pos].second;
ans+=(x+shu[xr][pos].first)/sum*n;
cout<<ans<<endl;
}
}
}
}