codeforces 763 C Timofey and remoduling(数学)

96 篇文章 0 订阅
64 篇文章 0 订阅

题意:

给出序列a,质数m,序列长n,序列a是对m取模后的序列,问是否能找到一个原序列是等差数列,输出首项和公比。否则输出-1。


解题思路:

首先需要知道两个公式:

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;

           int tmp=1LL*n*x%m*x%m;
        tmp=(tmp+1LL*n*(n-1)%m*d%m*x%m)%m;
        tmp=(tmp+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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值