Description
有一个未知的序列x,长度为n。它的K-划分序列y指的是每连续K个数的和得到划分序列,y[1]=x[1]+x[2]+….+x[K],y[2]=x[K+1]+x[K+2]+….+x[K+K]….。若n不被K整除,则y[n/K+1]可以由少于K个数加起来。比如n=13,K=5,则y[1]=x[1]+…+x[5],y[2]=x[6]+….+x[10],y[3]=x[11]+x[12]+x[13]。若小A只确定x的K[1]划分序列以及K[2]划分序列….K[M]划分序列的值情况下,问她可以确定x多少个元素的值。
Input
第一行输入两个正整数n,M。
第二行输入M个正整数表示K[1],K[2]…..K[M]。
Output
输出1个整数,表示能确定的元素
Sample Input
【输入样例1】
3 1
2
【输入样例2】
6 2
2 3
【输入样例3】
123456789 3
5 6 9
Sample Output
【输出样例1】
1
【输出样例2】
2
【输出样例3】
10973937
Data Constraint
对于20%的数据,3 <= N <= 2000,M<=3。
对于40%的数据,3 <= N <= 5*10^6。
对于100%的数据,3 <= N <= 10^9 , 1 <= M <= 10,2 <= K[i] < N。
Hint
【样例1解释】
小A知道x的2-划分序列,即分别知道x[1]+x[2],x[3]的值。
小A可以知道x[3]的值。
【样例2解释】
小A知道x的2-划分序列,即分别知道x[1]+x[2],x[3]+x[4],x[5]+x[6] 的值。
小A知道x的3-划分序列,即分别知道x[1]+x[2]+x[3] ,x[4]+x[5]+x[6] 的值。
小A可以知道x[3],x[4]的值,个数为2.
分析:
我们发现,对于一个位置
能被计算出,存在
和
,满足
且
。
也就是
,即
。这个可以用扩展欧几里得求出。然后就是去重了,显然一个数可能会被不同的式子表出。可以用容斥弄掉。
例如:
……
……
这两个式子可以表示为
这样就也可以用扩展欧几里得算出。容斥系数为式子数的奇偶性。答案数显然就是
的个数,对于最后一个位置,可以判断他是否能独立出来,如果能就直接把这位统计答案,位置数减一。注意没有
这个位置,这个让我wa了好久。因为每个点的状态只有等于
,等于
,不在方程组内,所以复杂度是
的。
代码:
#include <iostream>
#include <cmath>
#include <cstdio>
#define LL long long
using namespace std;
LL a[20];
LL n,m,ans;
LL f[1024][1024];
LL gcd(LL x,LL y)
{
LL r=x%y;
while (r)
{
x=y;
y=r;
r=x%y;
}
return y;
}
LL getlcm(LL s)
{
LL lcm=1;
while (s)
{
LL t=s&(-s);
LL k=trunc(log(t+0.233)/log(2));
lcm=a[k+1]*lcm/gcd(a[k+1],lcm);
s-=t;
}
return lcm;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if (b==0)
{
x=1; y=0;
return a;
}
LL d=exgcd(b,a%b,x,y);
LL z=x;
x=y; y=z-a/b*y;
return d;
}
LL calc(LL a,LL b,LL c)
{
LL x,y;
LL g=exgcd(a,b,x,y);
if (c%g!=0) return 0;
{
LL k=b/g;
x=x%k;
while (x<=0) x+=k;
LL p=n/a;
return p/k+(x%k<=p%k);
}
}
LL getnum(LL x)
{
LL sum=0;
while (x)
{
sum++;
x-=x&(-x);
}
return sum;
}
int main()
{
freopen("sazetak.in","r",stdin);
freopen("sazetak.out","w",stdout);
scanf("%lld%lld",&n,&m);
for (LL i=1;i<=m;i++) scanf("%lld",&a[i]);
for (LL i=1;i<=m;i++)
{
if (n%a[i]==1)
{
ans++;
n--;
break;
}
}
for (LL s1=1;s1<(1<<m);s1++)
{
for (LL s2=1;s2<(1<<m);s2++)
{
if ((s1&s2)==0)
{
LL lcm1=getlcm(s1),lcm2=getlcm(s2);
f[s1][s2]=calc(lcm1,lcm2,1);
}
}
}
for (LL i=1;i<(1<<m);i++)
{
for (LL j=1;j<(1<<m);j++)
{
if ((i&j)==0)
{
LL k=getnum(i)+getnum(j);
if (k%2==0) ans+=f[i][j];
else ans-=f[i][j];
}
}
}
printf("%lld",ans);
}