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.
题解
题目给出某些位置的前缀和,然后问有多少个数是可以求出来的。
设前缀和为
si
s
i
如果这个位置x能被表示出来,当且仅当知道
sx
s
x
和
sx−1
s
x
−
1
转化一下:
x=
ki∗a
k
i
∗
a
x=
kj∗b+1
k
j
∗
b
+
1
移一下项:
a∗ki−b∗kj=1
a
∗
k
i
−
b
∗
k
j
=
1
是不是有点像扩建欧几里得的形式,
我们是要求
a∗ki
a
∗
k
i
在n里面有多少个整数解,
看一下怎样统计。
设a的最小正整数解为
a1,b1
a
1
,
b
1
那么a的通解就是a=
p∗b1+a1
p
∗
b
1
+
a
1
也就是说,我们要求有多少个p,
满足
p∗b1∗ki+a1∗b1
p
∗
b
1
∗
k
i
+
a
1
∗
b
1
≤n
这个就很简单了。
但是很显然,不能直接枚举i,j因为这样会算重。
而且题目的n这么小,很自然地想到容斥。
我们设A表示所有a方程的集合,对应着的,同样B表示所有b的方程。
这样每一个
ki
k
i
只会存在于要么A,要么B,要么两者都不。
这样枚举的复杂度是O(
3m
3
m
)的,
而容斥系数就是
(−1)|A|+|B|
(
−
1
)
|
A
|
+
|
B
|
,
这里涉及了同余方程的合并,就是他们的lcm。
code
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#define ll long long
#define N 100003
#define M 103
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(ll &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
ll n,m,k[13],x,y,ans,S,g,d,_3[13],a,b,t;
ll exgcd(ll a,ll b,ll& x,ll& y)
{
if(b==0)
{
x=1;y=0;return a;
}
else
{
ll d=exgcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
}
ll calc(ll a,ll b)
{
if(exgcd(a,b,x,y)!=1)return 0;
x=(x%b+b)%b;
if(n<x*a)return 0;
return (n-x*a)/(a*b)+1;
}
void dfs(ll s1,ll s2,int x,int n1,int n2)
{
if(s1>n || s2>n)return;
if(x>m)
{
if(n1 && n2)ans=ans+calc(s1,s2)*((n1+n2&1)?-1:1);
return;
}
dfs(s1*k[x]/exgcd(s1,k[x],a,b),s2,x+1,n1+1,n2);
dfs(s1,s2*k[x]/exgcd(s2,k[x],a,b),x+1,n1,n2+1);
dfs(s1,s2,x+1,n1,n2);
}
int main()
{
freopen("sazetak.in","r",stdin);
freopen("sazetak.out","w",stdout);
_3[0]=1;
for(int i=1;i<13;i++)
_3[i]=_3[i-1]*3;
read(n);read(m);
for(int i=1;i<=m;i++)
read(k[i]);
k[++m]=n;
dfs(1,1,1,0,0);
printf("%lld",ans);
return 0;
}