hdu 7130 Monopoly (多条件排序,分类讨论,map嵌套vector,排序小技巧,STL)

44 篇文章 0 订阅
13 篇文章 0 订阅

hdu 7130 Monopoly

分析:

  • 方法一:多条件排序 + + + 多条件二分

    方法二:用 m a p map map 嵌套 v e c t o r vector vector 来实现方法一

  • a [ i ] a[i] a[i] 前缀和得 s [ i ] s[i] s[i],设 d = s [ n ] d=s[n] d=s[n]

    即求是否存在 s [ i ] s[i] s[i],使得: x = s [ i ] + k d   ( k > = 0 ) x=s[i]+kd\ (k>=0) x=s[i]+kd (k>=0)

    根据题目要求, a n s = k n + i ans=kn+i ans=kn+i , 取答案最小值

    将上式同余 d d d,即: x ≡ s [ i ]   m o d   d   ( d > 0 ) x\equiv s[i]\bmod d\ (d>0) xs[i]modd (d>0)

  • 根据 d d d 的值要分三类情况讨论:

    • d = 0 d=0 d=0

      这种情况最简单,直接判断是否存在 s [ i ] = x s[i]=x s[i]=x 即可

    • d > 0 d>0 d>0

      因为 d > 0 d>0 d>0,故满足条件的 s [ i ] < = x s[i]<=x s[i]<=x

      对于多个满足条件的 s [ i ] s[i] s[i],要找使 a n s ans ans 最小的那一个

      可以想到是最大的,若有多个最大的,那就是出现在最前面的

    • d < 0 d<0 d<0

      这种情况乍一想很复杂,取模都取不动了

      可以通过取反的操作,将这种情况变成 d > 0 d>0 d>0 的情况

方法一:

#include <bits/stdc++.h>
#define int long long 
using namespace std;

const int N=1e5+5;
struct Node
{
    int w,id,mo;
    bool operator < (const Node &b) 
    { 
        return mo<b.mo || mo==b.mo && w<b.w || mo==b.mo && w==b.w && id>b.id;
        //先按模数大小排,若相等再按前缀和大小排,若还相等,再按下标大小排(下标下的在后面)
    }
}s[N];
int binary(int l,int r,int k,int mo)
{
    while(l<=r)
    {
        int mid=l+r>>1;
        if(s[mid].mo>mo || s[mid].mo==mo && s[mid].w>k) // mo相等,返回小于等于x的最后一个
            r=mid-1;
        else l=mid+1;
    }
    return r;
}
signed main()
{
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            int x;
            cin>>x;
            s[i].w=s[i-1].w+x;
            s[i].id=i;
        }
        int d=s[n].w, fg=0;
        if(d==0) 
        {
            for(int i=1;i<=n;i++) s[i].mo=s[i].w;
        }
        else 
        {
            if(d<0) //取反,注意是所有的都要取反
            { 
                fg=1; d=-d;
                for(int i=1;i<=n;i++) s[i].w=-s[i].w;
            }
            for(int i=1;i<=n;i++) s[i].mo=(s[i].w%d+d)%d;
        }
        sort(s+1,s+1+n); 
        //for(int i=1;i<=n;i++) cout<<s[i].mo<<' '<<s[i].id<<' '<<s[i].w<<endl;
        while(m--)
        {
            int x;
            cin>>x;
            if(x==0) { cout<<"0"<<endl; continue; }
            if(d==0)
            {
                int ans=binary(1,n,x,x);
                if(s[ans].mo!=x) cout<<"-1"<<endl; //不存在
                else cout<<s[ans].id<<endl;
            }
            else 
            {
                if(fg) x=-x; //输入的x也要取反,整体取反
                int mo=(x%d+d)%d;
                int p=binary(1,n,x,mo);
                if(p==0) { cout<<"-1"<<endl; continue; } 
                // 当mo=0的时候,特殊情况p会跑到最前面,如果不特判直接GG,s[0].mo=0
                if(s[p].mo!=mo) cout<<"-1"<<endl;
                else cout<<(x-s[p].w)/d*n+s[p].id<<endl;
            }
        }
    }
    return 0;
}

方法二:

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=1e5+5;
int s[N];
map <int, vector<pair<int,int> > >mp;
unordered_map <int,int> ma;
signed main()
{
    int T;
    scanf("%lld",&T);
    while(T--)
    {
        mp.clear(); ma.clear();
        int n,m;
        scanf("%lld%lld",&n,&m);
        s[0]=0;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%lld",&x);
            s[i]=s[i-1]+x;
        }
        int d=s[n],fg=0;
        if(d==0)
        {
            for(int i=1;i<=n;i++) if(!ma[s[i]]) ma[s[i]]=i;
            while(m--)
            {
                int x;
                scanf("%lld",&x);
                if(x==0) printf("0\n");
                else if(ma[x]) printf("%lld\n",ma[x]);
                else printf("-1\n");
            }
        }
        else
        {
            if(d<0)
            {
                d=-d; fg=1;
                for(int i=1;i<=n;i++) s[i]=-s[i];
            }
            for(int i=1;i<=n;i++) 
            {
                int mo=(s[i]%d+d)%d;
                mp[mo].push_back({-s[i],i}); // s[i]要从大到小排,故先取反,这scz也是惊到我了
            }
            for(auto u=mp.begin();u!=mp.end();u++)
            {
                sort(u->second.begin(),u->second.end()); // id从小到大
            }
            while(m--)
            {
                int x;
                scanf("%lld",&x);
                if(x==0) { printf("0\n"); continue; }
                if(fg) x=-x;
                int mo=(x%d+d)%d;
                if(mp[mo].size()==0) printf("-1\n");
                else 
                {
                    pair <int,int> t={-x,0}; // 根s[i]同步取反
                    int p=lower_bound(mp[mo].begin(),mp[mo].end(),t)-mp[mo].begin();
                    // 返回大于等于-x的第一个
                    if(p==mp[mo].size()) printf("-1\n"); //没找到
                    else 
                    {
                        int ans=mp[mo][p].second;
                        ans+=(x+mp[mo][p].first)/d*n;
                        printf("%lld\n",ans);
                    }
                }
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yezzz.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值