2019 浙江省赛 B-Element Swapping

 签到八题之一

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6003

题目大意:懒~上边链接,题面通俗易懂。

思路:水水题。假设这样的数存在的话,我们分别设值为a,b;位置为ax,bx。

设题目给的两个式子,设

\sum_{i=1}^{n}i*ai =sum1

\sum_{i=1}^{n}i*ai^2=sum2

然后X,Y如题目所给,代表我们交换以后的目标公式值。我们可得关系式

sum1-a*ax-b*bx+a*bx+b*ax=X

sum2-a^{2}*ax-b^{2}*bx+a^{2}*bx+b^{2}*ax=Y

化简得:

(a-b)*bx+(b-a)*ax=X-sum1                    式子1

(a^{2}-b^{2})*bx+(b^{2}-a^{2})*ax=Y-sum2             式子2

我们观察两个等式的左半部分,显然有(a+b)*((a-b)*bx+(b-a)*ax)=(a^{2}-b^{2})*bx+(b^{2}-a^{2})*ax

Y-sum2=(X-sum1)*(a+b)

b=\frac{Y-sum2}{X-sum1}

这样便可确定b的值唯一,且能求出b的值。

再把所有参数代入(a-b)*bx+(b-a)*ax=X-sum1 中,可得

bx=\frac{X-sum1-(b-a)*ax}{a-b}

代表bx也为定值,且可求出来。

这样一来,我们只需要判断bx位置的值是否为b即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100005];
unordered_map<ll,ll >mp;
int main()
{
    int n,t,m,i,j;
    ll x,y,ans,num,sum1,sum2,b,k;
    scanf("%d",&t);
    while(t--)
    {
        ans=sum1=sum2=0;
        scanf("%d%lld%lld",&n,&x,&y);
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum1+=a[i]*i;
            sum2+=a[i]*a[i]*i;
            mp[a[i]]++;
        }
        if(x==sum1&&y==sum2)
        {
            for(i=1;i<=n;i++) // 已经符合目标要求,每个数可任意与其他位置的该数交换(即值相同位置不用任意交换)
            {
                num=mp[a[i]];
                if(num==0)
                    continue;
                ans+=(num*(num-1))/2; //等差数列求和
                mp[a[i]]=0;
            }
            printf("%lld\n",ans);
        }
        else if(x!=sum1&&y!=sum2&&((y-sum2)%(x-sum1))==0) // 不符合目标要求时,根据公式,除数不能为0即(x-sum1)不为0。而若y==sum2,b=-a也不可能,顺便排除掉减点时间
        {
            num=(y-sum2)/(x-sum1);
            for(i=1;i<=n;i++)
            {
                b=num-a[i];
                if(a[i]!=b&&(x-sum1-(b-a[i])*i)%(a[i]-b)==0) //k一定是整数,不能整数代表不存在,就不计算了,同时得先保证除数不为0
                {
                    k=(x-sum1-(b-a[i])*i)/(a[i]-b);
                    if(k<=n&&k>=1&&a[k]==b) // 注意要避免越界访问
                    {
                        ans++;
                    }
                }
            }
            printf("%lld\n",ans/2);
        }
        else
        {
            printf("0\n");
        }
        for(i=1;i<=n;i++) //每一次结束都要初始化mp 虽然说跟第一种情况一遍的赋0有点重复,你想节省点时间自然可以把这部直接放二、三情况里边,因为一情况不是主要情况所以我懒改了(时间省不了多少的意思)
            mp[a[i]]=0;
    }
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值