[Luogu5181][COCI2009]GENIJALAC
Posted lanrtabe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Luogu5181][COCI2009]GENIJALAC相关的知识,希望对你有一定的参考价值。
题目链接:
一个简单题?
首先对([C+1,n-D])中的每个数字求出循环节,求(Lcm)即是整段的循环节。
然后判断([A,B])中有几个数满足(x-1equiv 0(mod Lcm))。
求循环节暴力可过。。
其实求循环节是可以(O(n))的。
每一次求循环节得到一个环,那么环上所有点的循环节都是此次求出的循环节。
那么就可以(O(n))得到所有循环节。
代码:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
typedef long long ll;
const ll llMax=1e13;
ll Gcd(const ll a,const ll b){return b?Gcd(b,a%b):a;}
ll Lcm(const ll a,const ll b){return a/Gcd(a,b)*b;}
int n,s[500005];
bool v[500005];
ll a,b,c,d,Mfo=1;
void DFS(const int x,const int St,const int Nt)//x 现在的位置 St 此次起点 Nt 已经经过节点数
{
if(v[x])
{
if(x!=St)puts("0"),exit(0);//形成环,但是St不在环上,即St没有循环节
Mfo=Lcm(Mfo,Nt);//求Lcm
if(Mfo>=llMax)puts("0"),exit(0);//循环节过大,那么[A,B]中没有满足要求的数
return;
}
v[x]=true,DFS(s[x],St,Nt+1);
}
int main()
{
std::cin>>n>>a>>b>>c>>d;
for(int i=1;i<=n;++i)scanf("%d",&s[i]);
for(int i=c+1;i<=n-d;++i)
if(!v[i])DFS(i,i,0);//不求减去的
ll l=std::max(a-1,(ll)1),r=std::max(b-1,(ll)1);//把[A,B]中所有数-1,求有多少数是Lcm的倍数
if(l%Mfo)l=(l/Mfo+1)*Mfo;
if(r%Mfo)r=r/Mfo*Mfo;
std::cout<<(r-l)/Mfo+1+(a==1)<<std::endl;//特判第1个
return 0;
}
以上是关于[Luogu5181][COCI2009]GENIJALAC的主要内容,如果未能解决你的问题,请参考以下文章
Luogu5307 [COCI2019] Mobitel 数论分块递推
Luogu_4329 [COCI2006-2007#1] Bond
luogu P5052 [COCI2017-2018#7] Go