凑方程解

题目描述
小明正在为一个化学方程式解一个四元一次方程,已知A*x1+B*x2+C*x3+D*x4=P,其中x1,x2,x3,x4是未知数,A,B,C,D是已知的系数。可是这个方程的解实在是太多了,经过一系列运算,小明确定了4个未知数只可能从一个包含了N个正整数的S[]数组中产生,每个未知数都可以从S[1]到S[N]中选择,不同未知数选的值可以相同。保证S数组中所有的数字都不相同。
现在已知A,B,C,D,P,N,以及N个整数,问共有多少组方程的解。

输入
第一行6个整数A,B,C,D,P,N,分别表示方程的系数和S数组中的元素个数。
第二行N个正整数,表示S数组中的元素。

输出
一个整数,表示方程的解的数量。(未知数的值只能从S数组中产生,其他的解即使符合条件也不计入答案中)。

样例输入
1 1 1 1 4 4
1 2 3 4
样例输出
1

提示
【样例解释】
当x1=x2=x3=x4=1时,等式成立。
【数据范围】
对于40%的数据,N<=50。
对于70%的数据,N<=200。其中系数的绝对值|A|,|B|,|C|,|D|均小于500,|P|<=10^6,S数组中每个元素|s[i]|<=500
对于100%的数据,N<=1000,其中系数的绝对值|A|,|B|,|C|,|D|均小于10000,|P|<=4*10^13,S数组中每个元素|s[i]|<=10^9。

Solution

b数组记录A*s[i]+B*s[j]
c数组记录C*s[i]+D*s[j]
枚举b,在c里二分找p-b[i]
但是这样还是有点慢,我们可以加个小优化(从单调性考虑,可以先自己思考一下)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll A,B,C,D,p,w,ans;
ll b[1000005],c[1000005];
int n,len,up,down;
int a[1005];
int erfen1(int l,int r,ll x) //二分找上界
{
    if(l>r) return r;
    int mid=(l+r)/2;
    if(x>=c[mid]) return erfen1(mid+1,r,x); else return erfen1(l,mid-1,x);
}
int erfen2(int l,int r,ll x) //二分找下界
{
    if(l>r) return l;
    int mid=(l+r)/2;
    if(x<=c[mid]) return erfen2(l,mid-1,x); else return erfen2(mid+1,r,x); 
}
int main()
{
    cin>>A>>B>>C>>D>>p>>n;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) 
    for(int j=1;j<=n;j++) 
    {
        len++;
        b[len]=A*a[i]+B*a[j];
        c[len]=C*a[i]+D*a[j];
    }
    sort(b+1,b+len+1);
    sort(c+1,c+len+1);
    w=len;
    int i=1;
    while(1) 
    {
        up=erfen1(1,w,p-b[i]);
        down=erfen2(1,w,p-b[i]);
        if(c[up]==p-b[i]&&c[down]==p-b[i]) ans=ans+up-down+1;
        while(i<len&&b[i+1]==b[i]) //后面一样直接用当前结果
        {
            i++;
            ans=ans+up-down+1;
        }
        i++;
        if(i>len) break; 
        w=down-1; //缩小二分范围
    }
    cout<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值