/**//* 题意:1,2,N这个序列,给出一个变换的序列next[],现不断变换 求变换A到B次的,在范围[C+1,N-D]的数等于原来位置的序列的个数 可以O(n)找出每个数的循环节,dfs 然后总的周期 P = LCM(cycle[ C+1 ],…, cycle[ N-D ] ) 然后答案就是solve(B) - solve(A-1)
题目应该不算非常难,但我还是想不到,可能不熟悉了 */ #include<cstdio> #include<cstring> #include<algorithm>
using namespace std;
const int MAXN = 500010;
int cycle[MAXN],next[MAXN]; int N; long long period;
int dfs(int x ,int pos, int len)//O(n)找所有点的循环节 { if( x == pos && len > 0 )return len; return cycle[x] = dfs( x ,next[pos] , len+1 ); }
long long gcd( long long a, long long b) { return b ? gcd( b, a%b ) : a ; }
inline long long lcm( long long &a, long long b ) { return a / gcd( a ,b ) * b; }
long long solve(long long x) { return ( x + period -1 ) / period;//上界要这样子写 //写成(x-1)/p+1的话0的上界变为1了 }
int main() { freopen( "in", "r", stdin); long long A,B; int C,D; while( ~scanf("%d%lld%lld%d%d",&N,&A,&B,&C,&D) ) { C ++ ; D = N - D; for( int i=1; i<=N; i++ ) scanf( "%d", &next[i] );
memset( cycle, -1, sizeof( cycle ) ); for( int i=1; i<=N; i++ ) { if( cycle[i] == -1 ) dfs( i, i, 0 ); } period = 1; for( int i=C; i<=D ;i++ ) { period = lcm( period , cycle[i] ); if(period > B){ period = B+1; break; } } printf("%lld\n", solve(B) - solve(A-1)); } return 0; }
|