题目链接
Monopoly - HDU 7130 - Virtual Judge
题目大意
题目思路
先处理好前缀和sum【i】
将这个sum【i】放入set【sum【i】%sum【n】】中
对于m个询问x
看在set【x%sum【n】】的size是多少
如果是0则输出-1
否则找到大于他或者小于他离他最近的那个sum【i】(找法与sum【n】正负有关)
然后用|x-sum[i]|/sum[n]*n(循环了几行)+这个sum【i】在每一行的位置
利用set自动排序和去重 利用map离散化
另外要注意别忘了忽视余数是负数的情况
比如如下hack
/*
1 10 10
3 0 -8 5 9 8 7 6 6 2
26 -64 74 -97 91 -19 -19 -47 33 51
*/
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
int t,n,mm,cnt;
set<ll >s[maxn];
map<ll ,int > m,mpos;
ll sum[maxn],tot;
void init()
{
map<ll,int >::iterator itt;
for(itt=m.begin();itt!=m.end();itt++)
{
s[itt->second].clear();
}
m.clear();
mpos.clear();
cnt=0;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("WA.out","w",stdout);
cin>>t;
while(t--)
{
cin>>n>>mm;
init();
ll tmp;
for(int i=1;i<=n;i++)
{
sum[i]=0;
scanf("%lld",&tmp);
sum[i]+=tmp+sum[i-1];
if(mpos[sum[i]]==0)
{
mpos[sum[i]]=i;
}
}
tot=sum[n];
if(tot!=0)
for(int i=1;i<=n;i++)
{
ll now=(sum[i]%tot+tot)%tot;//防止余数是负数的情况 这时候可能忽视了某种情况
if(m[now]==0)
{
m[now]=++cnt;
}
s[m[now]].insert(sum[i]);
}
ll x,ans;
set<ll >::iterator it;
for(int i=1;i<=mm;i++)
{
scanf("%lld",&x);
if(x==0)//特判
{
cout<<0<<endl;
continue;
}
if(tot==0)//特判
{
if(mpos[x]==0)
{
ans=-1;
}
else
{
ans=mpos[x];
}
cout<<ans<<endl;
continue;
}
ll now=m[(x%tot+tot)%tot];//防止余数是负数的情况 这时候可能忽视了某种情况
ll sz=s[now].size();
if(now==0||sz==0)//找不到余数相同的地方
{
cout<<-1<<endl;
continue;
}
if(tot>0)
{
it=s[now].upper_bound(x);
if(it==s[now].begin())
{
ans=-1;
}
else
{
it--;//找第一个小于等于它的
ans=(x-*it)/tot*n+mpos[*it];
}
}
else
{
it=s[now].lower_bound(x);//找第一个大于等于它的
if(it==s[now].end())
{
ans=-1;
}
else
{
ans=(x-*it)/tot*n+mpos[*it];
}
}
cout<<ans<<endl;
}
}
return 0;
}