【题目描述】:
神犇heheda最近得到了UOJ抱枕,蒟蒻yts1999想要玩。于是heheda给yts1999出了一道题:
一个长度为2n+2的整数数列 按照下式定义:
A0=0
A1=C
Ai+2=(Ai+1+Ai) Mod M (0<=i<=2*N)
现有n个平面向量v1…vn:
V1=(A2,A3),V2=(A4,A5)...Vn=(A2n,A2n+1)
集合S的定义如下:
其中"vi•vj"表示向量vi和vj的数量积。
求S集合中不同元素的个数是多少。答案对M取模。
heheda告诉yts1999,只要他做出了这道题,她就可以把抱枕借给他玩一会。然而yts1999实在是太弱了不会做,于是向你求助。
【题目解法】:
根据类斐波那契数列的性质:
F[1]*F[n+m+1]=F[n]*F[m]+F[n+1]*F[m+1]
F[1]*F[n+1]=F[m]*F[n-m]+F[m+1]*F[n-m+1]
因此对于两个向量:vi=(F[i],F[i+1]) vj=(F[j],F[j+1])
那么F[i]*F[j]+F[i+1]*F[j+1]=F[1]*F[i+j+1]
因此对于所有就是询问本质不同的F[i+j+1]*F[1]
i+j+1的范围是[7,4n-1]内所有的奇数,全部拉出来sort一发就好
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=2000005;
int n,maxmod,f[N],a[N],tot;
inline long long getint()
{
long long x=0; char c=getchar(); bool flag=false;
while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
if (c=='-') flag=true,c=getchar();
while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
if (flag) return -x; else return x;
}
void init()
{
f[1]=getint(); maxmod=getint(); n=getint(); tot=0;
for (int i=2; i<=4*n; i++) f[i]=(f[i-1]+f[i-2])%maxmod;
for (int i=6; i<=4*n-2; i+=2) a[++tot]=(long long)f[i+1]*f[1]%maxmod;
}
void solve()
{
sort(a+1,a+tot+1);
tot=unique(a+1,a+tot+1)-(a+1);
printf("%d\n",tot%maxmod);
}
int main()
{
init();
solve();
return 0;
}