CF1593 D2. Half of Same(set,清空数组优化小技巧)

53 篇文章 1 订阅
20 篇文章 0 订阅

D2. Half of Same

分析 (solution one):

  • 暴力枚举所有可能约数即可

    约数最大为 2 e 6 2e6 2e6 O ( n ∗ 2 e 6 ) O(n*2e6) O(n2e6),刚好卡过去

  • 由于是多组数据,要多次清空数组,这里有个优化的小技巧,详见代码

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

const int N=2e6+5;
int a[105];
int vis[N],cnt[N];
signed main()
{
    int T;
    cin>>T;
    int cas=0;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i], a[i]+=1e6;
        int ans=0;
        for(int i=N;i>0;i--)
        {
            cas++;
            int mx=0;
            for(int j=1;j<=n;j++)
            {
                int x=a[j]%i;
                if(vis[x]<cas) vis[x]=cas,cnt[x]=0; // 优化小技巧
                if(mx<++cnt[x]) mx=cnt[x];
            }
            if(2*mx>=n) 
            {
                ans=i;
                break;
            }
        }
        if(ans==N) puts("-1");
        else cout<<ans<<endl;
    }
}

分析 (solution two):

  • s e t set set 记录所有可能出现的约数( s e t set set 乱搞~)

  • 将所有的约数从大到小遍历

    再由 D 1 D1 D1 (见下文) 当中讲过的,以一个数为基准,判断所有数与这个数的差值是否能被约数整除

    若满足条件的数超过 n 2 \frac{n}{2} 2n, 输出答案即可

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

int a[105];
set <int, greater<int> > sd,sp;
signed main()
{
    int T;
    cin>>T;
    int cas=0;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n);
        int cnt=1,sum=1;
        for(int i=2;i<=n;i++)
        {
            if(a[i]!=a[i-1]) sum=max(sum,cnt), cnt=1;
            else cnt++;
        }
        sum=max(sum,cnt);
        if(sum*2>=n) { puts("-1"); continue; }
        sd.clear(); sp.clear();
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                sd.insert(a[j]-a[i]);
            }
        }
        for(auto v : sd)
        {
            for(int j=1;j*j<=v;j++)
            {
                if(v%j==0)
                {
                    sp.insert(j); sp.insert(v/j);
                }
            }
        }
        int ans=1,fg=0;
        for(auto v : sp)
        {
            for(int i=1;i<=n/2+1 && !fg;i++)
            {
                int t=1;
                for(int j=i+1;j<=n;j++)
                {
                    if((a[j]-a[i])%v==0) t++;
                }
                if(t*2>=n) 
                {
                    ans=v;
                    fg=1;
                }
            }
            if(fg) break;
        }
        cout<<ans<<endl;
    }
}

D1. All are Same

分析:

  • 要求一个最大的 k k k 使得序列中的所有数加上若干个 k k k 之后相等
  • 计算所有差值的 g c d gcd gcd 即可
  • 但是没必要 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1) 个差值,以一个数为基准,计算所有数与这个数的差值即可
#include <bits/stdc++.h>
using namespace std;

const int N=105;
int gcd(int a,int b) { return b ? gcd(b,a%b) : a; }
int a[N];  
signed main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n);
        int ans=0;
        for(int i=2;i<=n;i++)
        {
            int d=a[i]-a[i-1]; // a[i]-a[1]也行
            if(d==0) continue;
            ans=gcd(d,ans);
        }
        if(!ans) puts("-1");
        else cout<<ans<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yezzz.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值