2019浙江省省赛 ZOJ 4101 Element Swapping 数学

博客给出ZOJ - 4101题目链接,分享题解思路。赛场原用O(nlogn)算法超时,后化简Δx和Δy,相除得到ai + aj的sum,不整除则输出0,再O(n)枚举i并代入验证,时间复杂度为O(n),还提醒注意特判和限制条件。

题目链接

https://vjudge.net/problem/ZOJ-4101

题解思路

赛场想的是 O ( n l o g n ) O(nlogn) O(nlogn)的算法,T了有20发

从头讲一下,就是化简一下 Δ \Delta Δ x x x Δ \Delta Δ y y y 这里我设的是变化前减去变化后,我们可以把数组看做是初始的,给定的x和y是变化后的。

化简完:
Δ \Delta Δ x = ( j − i ) ∗ ( a i − a j ) x=(j-i)*(a_i-a_j) x=(ji)(aiaj)
Δ \Delta Δ y = ( j − i ) ∗ ( a i + a j ) ∗ ( a i − a j ) y=(j-i)*(a_i+a_j)*(a_i-a_j) y=(ji)(ai+aj)(aiaj)

相除得到 a i + a j a_i+a_j ai+aj s u m sum sum,如果不整除输出0

然后 O ( n ) O(n) O(n)枚举 i i i a j aj aj= s u m − a i sum-a_i sumai,然后代入 Δ \Delta Δ x x x的式子中验证是否满足 a j = a j aj=a_j aj=aj

时间复杂度: O ( n ) O(n) O(n)

注意特判和限制条件

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define int ll
#define debug cout<<"fuck"<<endl;
#define pb  push_back
#define endl '\n'
const int mod=(int)1e9+7;
const int maxn=(int)1e5+5;
int n;
int a[maxn];
int x,y;
int xx,yy;
int delx,dely;
int cnt[maxn];
signed main()
{
    IOS
    int t;
    cin>>t;
    while(t--)
    {
        memset(cnt,0,sizeof(cnt));
        xx=0,yy=0;
        cin>>n>>x>>y;//原始的
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            cnt[a[i]]++;
            xx+=i*a[i];//交换一次后的
            yy+=i*a[i]*a[i];
        }
        delx=x-xx;
        dely=y-yy;
        //cout<<delx<<' '<<dely<<endl;
        if(delx==0&&dely==0)//相同值交换
        {
            //debug;
            int ans=0;
            for(int i=1;i<=1e5;i++)
            {
                if(cnt[i]>=2)
                {
                    ans+=cnt[i]*(cnt[i]-1)/2;
                }
            }
            cout<<ans<<endl;
            continue;
        }
        else if(delx==0||dely==0||dely%delx!=0)
        {
            //debug
            cout<<0<<endl;
            continue;
        }
        int sum=dely/delx;//ai+aj
        //cout<<sum<<endl;
        int res=0;
        for(int i=1;i<=n;i++)
        {
            int aj=sum-a[i];
            if(aj<1||(aj-a[i]==0)||(delx%(aj-a[i]))!=0)
            {
                continue;
            }
            int j=delx/(a[i]-aj)+i;
            if(j>n||j<1)continue;
            //cout<<i<<' '<<aj<<' '<<j<<endl;
            if(aj==a[j])res++;
        }
        cout<<res/2<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值