跳到主要内容

[CF2044F]Easy Demon Problem 解题思路

2024-12-18

CF2044F Easy Demon Problem

题目大意

给定两个长度为 n,mn,mn,m 的数列 aia_iai​ ,bjb_jbj​ ,并且依据该数列构造一个矩阵 Mn,mM_{n,m}Mn,m​,使得 Mi,j=ai×bjM_{i,j}=a_i \times b_jMi,j​=ai​×bj 。

再给出 qqq 个查询,对于每个 xix_ixi​,查找是否存在一对 i,ji,ji,j 使得该矩阵删去第 iii 行和第 jj 列,使得矩阵剩下所有数之和为 。

每一组询问是独立的。

思路

我们发现,矩阵之和可以写为 ∑i=0n∑j=0mai×bj\sum_{i=0}^{n}{\sum_{j=0}^{m}{a_i \times b_j} }∑i=0n​∑j=0m​ 可以变形为

∑i=0nai×∑j=0mbi\sum_{i=0}^{n}{a_i} \times \sum_{j=0}^{m}{b_i}∑i=0n​ai​×∑

上式等价于 sum(a)×sum(b)sum(a) \times sum(b) sum(a)×sum(b)

我们神奇的发现,当删去这个矩阵的第 iii 行第 jjj 列的时候,矩阵里面的所有元素之和就是: [sum(a)−ai]×[sum(b)−bj][sum(a)-a_i]\times[sum(b)-b_j][sum(a)−ai​

我们的目的就转换为求是否有一对 aia_iai​ 和 bjb_jbj​ 使得 [sum(a)−ai]×[sum(b)−bj]=x[sum(a)-a_i]\times[sum(b)-b_j]=x 。

重点: 我们分别记录每一个数组 a,ba,ba,b ,并分别求出他们的和。对于每一个询问 xxx ,分解 xxx 的因数,查找每一对因数 l,rl,rl,r ,假设 l=sum(a)−ai,r=sum(j)−b ,则问题又被转换为求是否存在 。这里考虑数据范围,开个大数组记录即可。

注意数存在负数需要处理,时间复杂度为 O(q)O(q)O(q) (有个 2⋅105\sqrt {2⋅10^5}2⋅105​ 的常数)可过。

参考代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
bool ina[500010],inb[500010];
int la[300010],lb[300010];
ll sum1=0,sum2=0;
bool checkin(bool f,ll num){
    if(num>250000||num<-250000)return false;
    if(!f)return ina[num+250000];
    return inb[num+250000];
}
bool checkit(ll a,ll b,int f){
    int fl1=1,fl2=1;
    if(f)fl1=-1;
    if(checkin(0,sum1-a*fl1)&&checkin(1,sum2-b*fl2))return true;
    if(checkin(1,sum2-a*fl1)&&checkin(0,sum1-b*fl2))return true;

    fl1=-fl1,fl2=-fl2;

    if(checkin(0,sum1-a*fl1)&&checkin(1,sum2-b*fl2))return true;
    if(checkin(1,sum2-a*fl1)&&checkin(0,sum1-b*fl2))return true;
    return false;

}
int main()
{
    //freopen("read.in","r",stdin);
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;++i)scanf("%d",&la[i]),sum1+=la[i],ina[la[i]+250000]=true;
    for(int i=1;i<=m;++i)scanf("%d",&lb[i]),sum2+=lb[i],inb[lb[i]+250000]=true;
    for(int i=1;i<=q;++i){
        int x;
        scanf("%d",&x);
        int f=0;
        if(x<0)f=1,x=-x;

        for(int j=1;j<=sqrt(x);++j){
            if(x%j==0){
                if(checkit(j,x/j,f)){
                    printf("Yes\n");
                    f=2;
                    break;
                }
            }
        }
        if(f==2)continue;
        printf("No\n");
    }
}
←返回列表
© 2026 MisakaE
​
j
xix_ixi​
ai​×bj​
j=0m
​
bi​
]
×
[sum(b)−
bj​]
[sum(a)−ai​]×[sum(b)−bj​]=x
jl=sum(a)-a_i,r=sum(j)-b_j
l=sum(a)−ai​,r=sum(j)−bj​
ai=sum(a)−l,bj=sum(j)−ra_i=sum(a)-l,b_j=sum(j)-rai​=sum(a)−l,bj​=sum(j)−r