Codedigger Training Contest -Number Theory G. Singhal and Multiplication(数论)

G. Singhal and Multiplication(数论)

题目链接:https://codeforces.com/gym/102767/problem/G
题目大意:给定一段序列 { a 1 , a 2 , ⋯   , a n } \{a_1,a_2,\cdots,a_n\} {a1,a2,,an},要你寻找一段连续子序列 { a i , ⋯   , a j } ( 1 ≤ i ≤ j ≤ n ) \{a_i,\cdots ,a_j\}(1 \le i \le j \le n) {ai,,aj}(1ijn),使得 ∏ k = i j a k ≡ 1   m o d   n \prod \limits_{k=i}^{j}a_k \equiv 1 \space mod \space n k=ijak1 mod n。如果存在这样的子序列,输出 m i n ( j − i + 1 ) min(j-i+1) min(ji+1),即这样的子序列的最小长度,反之不存在的话就输出 0 0 0
题解:考虑逆元的定义,对于任意一个满足gcd(m,n) ≠ \neq = 1的整数m,则m在模n意义下不存在逆元。假设连续子序列 { a 1 , ⋯   , a r , ⋯   , a i , ⋯   , a j } \{a_1,\cdots ,a_r,\cdots ,a_i,\cdots ,a_j \} {a1,,ar,,ai,,aj},则有 ∏ k = r j a k ≡ ∏ t = r i − 1 a t   m o d   n \prod \limits_{k=r}^{j}a_k \equiv \prod \limits_{t=r}^{i-1}a_t\space mod \space n k=rjakt=ri1at mod n,其中gcd( a r − 1 a_{r-1} ar1,n) ≠ 1 ⇒ ∏ k = 1 r − 1 a k ≡ 0   m o d   n \neq 1 \Rightarrow \prod \limits_{k=1}^{r-1}a_k \equiv 0 \space mod \space n =1k=1r1ak0 mod n ∏ k = i j a k ≡ 1   m o d   n \prod \limits_{k=i}^{j}a_k \equiv 1 \space mod \space n k=ijak1 mod n。易知,我们不需要考虑位置r之前的子序列的影响,因为子序列是连续的,如果子序列拓展到位置r之前的元素,会令子序列一定会包含元素 a r − 1 a_{r-1} ar1,使得子序列的模n意义下的连乘结果不可能为1。记zpos为当前序列元素之前的最后一个满足gcd( a z p o s a_{zpos} azpos,n) ≠ \neq = 1的序列元素下标位置;记prepro为序列的前缀积,同时如果发现当前处理的位置i的前缀积为0时(即 ∏ k = z p o s + 1 i a k ≡ 0   m o d   n \prod \limits_{k=zpos+1}^i a_k \equiv 0 \space mod \space n k=zpos+1iak0 mod n),令prepro[i]只等于 a i a_{i} ai,这样处理的话我们便能保证prepro中的元素一直不会为0(除非 a i ≡ 0   m o d   n a_i\equiv 0 \space mod \space n ai0 mod n);记pro记录前缀积结果的出现位置,这样我们便能确定是否有同样的前缀积结果出现,还能得到这组子序列的长度,同样的,如果发现当前处理的位置i的前缀积为0时,把pro进行清空操作,因为 a i a_i ai之前的序列元素会影响后续子序列连乘的结果,使得连乘结果永远不能为1。
下面便是根据上面解题思路得出的AC代码(记得开long long,否则会被卡WA)。

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct fastio{fastio(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);}}fio;
signed main(){
    int t,n,m;
    cin>>t;
    while(t--){
        cin>>n;
        vector<int> prepro(n+1,0);
        map<int,int> pro;
        int res=0x3f3f3f3f,zpos=0;
        for(int i=1;i<=n;++i){
            cin>>m;
            m%=n;
            if(m==1) res=1;
            if(__gcd(m,n)!=1){
                prepro[i]=0;
                zpos=i;
                pro.clear();
                continue;
            }
            if(!prepro[i-1]) prepro[i]=m;
            else prepro[i]=(prepro[i-1]*m)%n;
            if(prepro[i]==1) res=min(res,i-zpos);
            if(pro.count(prepro[i])) res=min(res,i-pro[prepro[i]]);
            if(prepro[i]) pro[prepro[i]]=i;
        }
        cout<<(res==0x3f3f3f3f?0:res)<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值