Irrelevant Elements
Time Limit: 3000MS
Memory Limit: Unknown
64bit IO Format: %lld & %llu
Young cryptoanalyst Georgie is investigating different schemes of generating random integer numbers
ranging from 0 to m − 1. He thinks that standard random number generators are not good enough, so
he has invented his own scheme that is intended to bring more randomness into the generated numbers.
First, Georgie chooses n and generates n random integer numbers ranging from 0 to m − 1. Let
the numbers generated be a1, a2, … , an. After that Georgie calculates the sums of all pairs of adjacent
numbers, and replaces the initial array with the array of sums, thus getting n−1 numbers: a1 +a2, a2 +
a3, … , an−1 + an. Then he applies the same procedure to the new array, getting n − 2 numbers. The
procedure is repeated until only one number is left. This number is then taken modulo m. That gives
the result of the generating procedure.
Georgie has proudly presented this scheme to his computer science teacher, but was pointed out that
the scheme has many drawbacks. One important drawback is the fact that the result of the procedure
sometimes does not even depend on some of the initially generated numbers. For example, if n = 3
and m = 2, then the result does not depend on a2.
Now Georgie wants to investigate this phenomenon. He calls the i-th element of the initial array
irrelevant if the result of the generating procedure does not depend on ai
. He considers various n and
m and wonders which elements are irrelevant for these parameters. Help him to find it out.
Input
Input file contains several datasets. Each datasets has n and m (1 ≤ n ≤ 100 000, 2 ≤ m ≤ 109
) in a
single line.
Output
On the first line of the output for each dataset print the number of irrelevant elements of the initial
array for given n and m. On the second line print all such i that i-th element is irrelevant. Numbers
on the second line must be printed in the ascending order and must be separated by spaces.
Sample Input
3 2
Sample Output
1
2
通过画图观察,问题变成组合数 C(n-1,i) i∈[0,n-1] 中m的倍数是那些
由于m不一定是质数,所以不可以使用组合数线性递推公式,因为m的逆不一定存在,但是可以用另一个求逆元的公式
如果不使用合数逆元公式, 那么可以把 m 分解, 如果组合数中相同质数的指数更大,那么可以整除
由于从0开始到n-1, 那么时间复杂度 O(n)
又m的质因子不超过20个
那么可以在3000ms内解决此题
但是要注意当m剩一个大于sqrt(1e9) 的质数时, rev_p 数组存不下, 此时需要特判!
另一个RE的地方: 后面组合数公式递推时,如果这个质数不在m内,那么需要舍弃,否则RE
另外注意输出0的时候要有两个换行!!(注意读题)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 100005;
const int maxp = 20;
int prime[maxp]; // specific primes of m
int prime_m[maxp]; // cnt of m
int rev_p[maxn]; // reflection of prime in m
int prime_cnt;
inline bool get_m(int m)
{
memset(prime_m,0,sizeof(prime_m));
memset(rev_p,0,sizeof(rev_p));
prime_cnt=0;
int tmp = (int) sqrt(m+0.5);
for(int i=2;i<=tmp;i++) if(m%i==0)
{
prime[++prime_cnt] = i; rev_p[i] = prime_cnt;
while(m%i==0) prime_m[prime_cnt]++ , m/=i;
}
if(m>maxn-5) return false;
if(m>1) prime[++prime_cnt]=m , prime_m[prime_cnt]++ ,rev_p[m] = prime_cnt;
return true;
}
int current[maxp];
inline bool check()
{
for(int i=1;i<=prime_cnt;i++)
if(current[i]<prime_m[i]) return false;
return true;
}
int ans[maxn];
int cnt;
void work(int n)
{
cnt = 0;
if(check()) ans[++cnt] = 1;
for(int i=1;i<=n;i++)
{
int a = n - i + 1 , lima = (int) sqrt(a+0.5);
int b = i , limb = (int) sqrt(b+0.5);
for(int j=2;j<=lima;j++) if(a%j==0)
while(a%j==0)
{
a/=j;
if(rev_p[j]) current[rev_p[j]]++; // only the reflevtion exists, update!!!!!!
}
if(a>1 && rev_p[a]) current[rev_p[a]]++;
for(int j=2;j<=limb;j++) if(b%j==0)
while(b%j==0)
{
b/=j;
if(rev_p[j]) current[rev_p[j]]--; // only the reflevtion exists, update!!!!!!
}
if(b>1 && rev_p[b]) current[rev_p[b]]--;
if(check()) ans[++cnt] = i+1;
}
}
inline void print()
{
printf("%d\n",cnt);
if(!cnt) return;
for(int i=1;i^cnt;i++) printf("%d ",ans[i]);
printf("%d",ans[cnt]);
}
int main()
{
freopen("elements.in","r",stdin);
freopen("elements.out","w",stdout);
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(!get_m(m))
{
printf("0\n\n");
continue;
}
work(n-1);
print();
printf("\n");
}
return 0;
}