洛谷P8178「EZEC-11」Sequence 题解

题目传送门:P8178 「EZEC-11」Sequence

【题意】

  • 已知数列 f f f 满足 f i = a i ⋅ f i − 1 + b i ( i ≥ 1 ) f_i=a_i\cdot f_{i-1}+b_i(i\ge1) fi=aifi1+bi(i1)

  • 问是否存在非负整数 f 0 f_0 f0 ,使得 f i f_i fi质数 p i p_i pi 1 ≤ i ≤ n 1\le i \le n 1in )的倍数。

  • 本题有多组测试数据,若存在满足条件的 f 0 f_0 f0 则输出Yes,否则输出No

  • 对于 100 % 100\% 100% 的数据, 1 ≤ T ≤ 10 1\le T\le10 1T10 1 ≤ n ≤ 1 0 3 1\le n\le10^3 1n103 0 ≤ a i , b i ≤ 1 0 9 0\le a_i,b_i\le 10^9 0ai,bi109 2 ≤ p i ≤ 1 0 9 2\le p_i\le 10^9 2pi109 p p p质数

【分析】

  • 前置条件:看懂题目,已经会打暴力
  • 最先想到的肯定是枚举 f 0 f_0 f0 ,若有满足的则输出Yes,否则输出No,但这样的时间复杂度为 O ( max ⁡ ( f 0 , l c m ( p 1 , 2 , … , n ) ) ⋅ n 2 ) O ( \max(f_0,lcm(p_{1,2,\ldots,n}))\cdot n^2 ) O(max(f0,lcm(p1,2,,n))n2)
  • 代码类似这样:
    while(f[0]<gcd(all:p[1-n]))
    {
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            f[i]=a[i]*f[i-1]+b[i];
            if(f[i]%p[i])
            {
                flag=1;
                break;
            }
        }
        if(!flag)
        {
            printf("%d",f[0]);
        }
        ++f[0];
    }
  • 看到 n 2 ≤ 1 0 6 n^2\le10^6 n2106 和输出YesNo想到这是一道数学结论题,考虑去掉 max ⁡ ( f 0 , l c m ( p 1 , 2 , … , n ) ) \max(f_0,lcm(p_{1,2,\ldots,n})) max(f0,lcm(p1,2,,n))
  • 想到可以将 f i f_i fi c i ⋅ f 0 + d i c_i \cdot f_0+d_i cif0+di 表示,改变 f 0 f_0 f0 后可以用 O ( 1 ) O(1) O(1)的时间复杂度直接求出 f i f_i fi
  • 先不考虑 p i p_i pi ,看一下数组 c c c与数组 d d d 的规律:
i i i c c c d d d
000
1 a 1 a_1 a1 b 1 b_1 b1
2 a 1 ⋅ a 2 a_1 \cdot a_2 a1a2 ( b 1 ) ⋅ a 2 + b 2 (b_1) \cdot a_2+b_2 (b1)a2+b2
3 a 1 ⋅ a 2 ⋅ a 3 a_1 \cdot a_2 \cdot a_3 a1a2a3 ( b 1 ⋅ a 1 + b 2 ) ⋅ a 3 + b 3 (b_1 \cdot a_1+b_2) \cdot a_3+b_3 (b1a1+b2)a3+b3
4 a 1 ⋅ a 2 ⋅ a 3 ⋅ a 4 a_1 \cdot a_2 \cdot a_3 \cdot a_4 a1a2a3a4 ( ( b 1 ⋅ a 1 + b 2 ) ⋅ a 3 + b 3 ) ⋅ a 4 + b 4 ((b_1 \cdot a_1+b_2) \cdot a_3+b_3) \cdot a_4+b_4 ((b1a1+b2)a3+b3)a4+b4
  • 眼尖的同学应该已经发现了 c , d c,d c,d 数组的规律:
  • c i = c i − 1 ⋅ a i c_i=c_{i-1}\cdot a_i ci=ci1ai
  • d i = d i − 1 ⋅ a i + b i d_i=d_{i-1}\cdot a_i + b_i di=di1ai+bi
  • 于是代码变成了这样:
    c[0]=1;
    for(int i=1; i<=n; i++) {
        c[i]=c[i]*a[j];
        d[i]=d[i]*a[j]+b[j];
    }
  • 很短吧~
  • 但是! c i , d i c_i,d_i ci,di 可能变得很大很大,所以需要当场   m o d   p i \bmod p_i modpi
  • c i ⋅ f 0 + d i ≡ c i   m o d   p i ⋅ f 0 + d i   m o d   p i (   m o d   p i ) c_i \cdot f_0+d_i\equiv c_i\bmod p_i\cdot f_0+d_i\bmod p_i(\bmod p_i) cif0+dicimodpif0+dimodpi(modpi)
  • 考虑 p i p_i pi f i f_i fi p i p_i pi 的倍数,即 f i   m o d   p i = 0 f_i\bmod p_i=0 fimodpi=0 ,使 c i = c i   m o d   p i c_i=c_i \bmod p_i ci=cimodpi d i = d i   m o d   p i d_i=d_i \bmod p_i di=dimodpi
  • 但是, p i p_i pi 不一定相同!所以针对每个 p i p_i pi用一个 O ( n ) O( n ) O(n)的循环求出 c i , d i c_i,d_i ci,di
  • 于是用 O ( n 2 ) O( n^2 ) O(n2)的预处理将这题转变成了另一个问题。

【简要题意】

给出 n n n c i c_i ci , d i d_i di , p i p_i pi ,求是否有满足所有公式 c i ⋅ x + d i ≡ 0 (   m o d   p i ) c_i\cdot x+d_i\equiv 0(\bmod p_i) cix+di0(modpi) 的通项 x x x

  • 很容易想到应该将 x x x 的系数化为1。
  • 但是!若 c i = 0 c_i=0 ci=0 ,就无法将 x x x 的系数化为1,但是!我们可以直接判断是否存在解了!
  • 考虑如何判断(这个应该比较简单),直接判断 d i   m o d   p i d_i\bmod p_i dimodpi 是否等于0,若不等于,则可以判断绝对是不存在解的,若等于则可以不考虑 i i i ,因为无论 x x x 等于几都必定有解
  • 那么若 c i c_i ci 不等于0,则将 d i d_i di 除上一个 c i c_i ci ,但我们已将 c i , d i   m o d   p i c_i,d_i\bmod p_i ci,dimodpi ,那么考虑求 p i p_i pi p x i px_i pxi ,这里就不做赘述
  • d i = d i ⋅ p x i   m o d   p i d_i=d_i\cdot px_i\bmod p_i di=dipximodpi
  • 于是用 O ( n log ⁡ n ) O( n\log n ) O(nlogn)的预处理又将这题转变成了另一个问题。
【简要题意】

给出 n n n d i d_i di , p i p_i pi ,求是否有满足所有公式 ( x + d i )   m o d   p i = 0 ( d i ≥ 0 ) (x+d_i)\bmod p_i=0(d_i\ge 0) (x+di)modpi=0(di0) 的通项 x x x

【分析】
  • 公式 ( x + d i )   m o d   p i = 0 (x+d_i)\bmod p_i=0 (x+di)modpi=0 x + d i x+d_i x+di p i p_i pi 的倍数
  • 所以化为 x = − d i ( f ( i ) ) x=-d_i(f(i)) x=di(f(i)) f ( i ) = ( i   m o d   p i + p i )   m o d   p i f(i)=(i\bmod p_i+p_i)\bmod p_i f(i)=(imodpi+pi)modpi
  • 使 f i = f ( d i ) f_i=f(d_i) fi=f(di)
  • 而保证 p i p_i pi 为质数,若 p i p_i pi 不同则一定有解,若 p i = p j p_i=p_j pi=pj f i f_i fi 不等于 f j f_j fj ,则必定无解,否则有解

【总结】

  • 以上全部判断完后若还全部满足则可以输出Yes

【代码】

#include<cstdio>
#include<unordered_map>
#define N 1009
#define int long long
using namespace std;
unordered_map<int,int>ma;
int t,n,flag;
int a[N],b[N],c[N],d[N],p[N];
int exgcd(int a, int b, int &x, int &y) { 
    if (!b) {
        x=1;y=0;
        return a;
    }
    int q=a/b,r=a%b,ex;
    ex=exgcd(b,r,y,x);
    y-=q*x;
    return ex;
}
main() {
    scanf("%lld",&t);
    while(t--) {
        flag=0;
        scanf("%lld",&n);
        for(int i=1; i<=n; i++)
            scanf("%lld",&a[i]);
        for(int i=1; i<=n; i++)
            scanf("%lld",&b[i]);
        for(int i=1; i<=n; i++)
            scanf("%lld",&p[i]);
        for(int i=1; i<=n; i++) {
            c[i]=1;
            d[i]=0;
            for(int j=1; j<=i; j++) {
                c[i]=c[i]*a[j]%p[i];
                d[i]=(d[i]*a[j]+b[j])%p[i];
            }
/*求c[i]与d[i],因为p[i]不同,所以针对每个p[i]都1~i枚举一遍
虽然时间复杂度变为了O(n^2),但没有超时~~~
而且不需要打高精了*/ 
            if(!c[i]&&d[i]) {
                puts("No");
                flag=1;
                break;
            }
            if(!c[i]) {
                p[i]=1e9;
//用一个非质数来代替p[i]防止与真正的p[i]重复
                d[i]=1e9;
                continue;
            }
            int t;
            exgcd(c[i],p[i],c[i],t);
            d[i]=(((-d[i])%p[i]+p[i])%p[i])*c[i]%p[i];
            d[i]=(d[i]+p[i])%p[i];
//将x的系数化为1 
        }
        if(!flag) {
            for(int i=1; i<=n; i++) {
                if(ma[p[i]]&&ma[p[i]]!=d[i]+1) {
                    puts("No");
                    break;
                } else {
                    ma[p[i]]=d[i]+1;
//+1是为了防止d[i]为0误判为没有存过
                }
                if(i==n) {
                    puts("Yes");
                }
            }
        }
        ma.clear();
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值