CodeForces 763C. Timofey and remoduling

来源:互联网 发布:海康威视网络摄像头 编辑:程序博客网 时间:2024/06/06 02:51

Little Timofey likes integers a lot. Unfortunately, he is very young and can't work with very big integers, so he does all the operations modulo his favorite prime m. Also, Timofey likes to look for arithmetical progressions everywhere.

One of his birthday presents was a sequence of distinct integers a1, a2, ..., an. Timofey wants to know whether he can rearrange the elements of the sequence so that is will be an arithmetical progression modulo m, or not.

Arithmetical progression modulo m of length n with first element x and difference d is sequence of integersx, x + d, x + 2d, ..., x + (n - 1)·d, each taken modulo m.

Input

The first line contains two integers m and n (2 ≤ m ≤ 109 + 71 ≤ n ≤ 105m is prime) — Timofey's favorite prime module and the length of the sequence.

The second line contains n distinct integers a1, a2, ..., an (0 ≤ ai < m) — the elements of the sequence.

Output

Print -1 if it is not possible to rearrange the elements of the sequence so that is will be an arithmetical progression modulo m.

Otherwise, print two integers — the first element of the obtained progression x (0 ≤ x < m) and its difference d (0 ≤ d < m).

If there are multiple answers, print any of them.

Examples
input
17 50 2 4 13 15
output
13 2
input
17 50 2 4 13 14
output
-1
input
5 31 2 3
output
3 4

题意:给定n,m和序列a,构造一个等差数列,使得它所有元素%m之后重排能够变成a,输出首项和公差

题解:智商题,不考算法,考脑洞

先考虑2*n<=m的情况

考虑a中的两个元素之差,假设它们在最后序列的位置为i,i+k,那么它们之差为k*d%m

由于保证2*n<=m所以这样的差只会出现n-k次,nlogn统计这个差出现的次数,于是我们就求出了k,从而求出了d,然后check即可

如果2*n>m

之前提到的差不会只出现n-k次,因为可能经过多遍,

那么把m内a的补集做一次,然后首项加上公差*项数即可(保证m是质数)

据说这题m不是质数也能做,有没有神犇教我一下啊QAQ

#include <bits/stdc++.h>    using namespace std;    const int MAXN = 100010;    int ans = -1, ansd, a[MAXN], b[MAXN], n, m;    inline int Pow(int x, int y, int mod)  {      int s = 1;      for( ; y ; y >>= 1, x = 1ll * x * x % mod ) if( y & 1 ) s = 1ll * s * x % mod;      return s;     }    inline bool find(int *a, int n, int x) { int t = lower_bound( a + 1, a + n + 1, x ) - a; return a[ t ] == x; }    inline void solve(int *a, int n)  {      if( n == 1 ) { ans = a[ 1 ], ansd = 1; return ; }       int tmp = a[ 2 ] - a[ 1 ], cnt = 0;      for( int i = 1 ; i <= n ; i++ ) if( find( a, n, ( a[ i ] + tmp ) % m ) ) cnt++;      ansd = 1ll * tmp * Pow( n - cnt , m - 2, m ) % m;      int d = ( m - ansd ) % m;      for( int i = 1 ; i <= n ; i++ ) if( !find( a, n, ( a[ i ] + d ) % m ) )      {          if( ans == -1 ) ans = a[ i ];          else { ans = -1; return ; }      }  }    int main()  {      scanf( "%d%d", &m, &n );      for( int i = 1 ; i <= n ; i++ ) scanf( "%d", &a[ i ] );      sort( a + 1, a + n + 1 );      if( n == 1 || n == m ) return printf( "%d 1\n", a[ 1 ], 1 ), 0;      if( 2 * n < m ) solve( a, n );      else      {          int t = 0;          for( int i = 0 ; i < m ; i++ ) if( !find( a, n, i ) ) b[ ++t ] = i;          solve( b, t );          if( ans != -1 ) ( ans += 1ll * ansd * t % m ) %= m;      }      if( ans == -1 ) return printf( "-1\n" ), 0;      return printf( "%d %d\n", ans, ansd ), 0;  }  


上面是q神的解法,下面还有一种解法:

解题思路:

首先需要知道两个公式:

1.等差数列各项和公式变形:a1=(Sn-n*(n-1)/2*d)/n

2.等差数列各项的平方的和的公式:Sn^2=n(a1)^2+n(n-1)(2n-1)d^2/6+n(n-1)*d*a1(以前不知道这公式。。)

先讲a序列从小到达排列,我们去枚举a[i]-a[0],因为a[i]中肯定有与a[0]相邻的点,所以我们一定能求出一个d,这个我已开始对一个特殊情况有疑问,问了q神后才知道,如果求不出d来,那么可以求出一个-d然后再加上就m就是合法的。

我想的特殊情况是a序列是2,4,6,8,对m为7取模后为1,2,4,6,这样的就求不出2这个公差了,但是问了q神之后知道,这样求出公差-2,对7取模后最小的数是8,因为和8相邻的点只有6了,那么就求出一个reverse过的公差-2(即6-8)的序列,在这里-2+m就是5,也就是6-1得到的数据。orz,模q

我们枚举出q后,可以根据公式1求出首项a1,这里由于除数有未知量,所以取模要求逆元,用费马小定理求一下就可以,然后再用公式2去验证是否满足来判断,d和a1是否正确。在这基础上还要确定下求出来的序列是否和a序列相同,相同就是符合的解了。


#include <bits/stdc++.h>  using namespace std;  const int maxn=1e5+5;  int a[maxn];  int b[maxn];  int fp(int a, int n,int  m)  {      int res=1;      int tem=a;      while(n)      {        if(n&1)res=1LL*res*tem%m;        tem=1LL*tem*tem%m;        n>>=1;      }      return res;  }  int main()  {    int n, m;    cin>>m>>n;        int i;    int s[2];    s[0]=s[1]=0;    for(i=0; i<n; i++)    {       scanf("%d", &a[i]);       s[0]=(a[i]+s[0])%m;       s[1]=(s[1]+1LL*a[i]*a[i]%m)%m;    }    if(n==1)return 0*printf("%d 0\n", a[0]);    if(n==m)return 0*printf("0 1");    sort(a, a+n);    for(int i=1; i<n; i++)    {      int d=(a[i]-a[0]);      int x=(s[0]-1LL*n*(n-1)/2%m*d%m+m)*fp(n,m-2,m)%m;      int tem=1LL*n*x%m*x%m;      tem=(tem+1LL*n*(n-1)%m*d%m*x%m)%m;      tem=(tem+1LL*n*(n-1)*(2*n-1)/6%m*d%m*d%m)%m;      if(s[1]==tem)      {      b[0]=x;      for(int i=1; i<n; i++)      {         b[i]=(b[i-1]+d)%m;      }      sort(b, b+n);  //  for(int i=0; i<n; i++)printf("%d ", b[i]);  //  printf("\n");      bool isok=true;      for(int i=0; i<n; i++)isok&=(a[i]==b[i]);      if(isok)return 0*printf("%d %d\n", x, d);      }    }    printf("-1\n");    return 0;  }  




0 0
原创粉丝点击