卧薪尝胆,厚积薄发。
POI2011 SEJ-Strongbox
Date: Mon Oct 29 20:21:10 CST 2018
In Category:
NoCategory
Description:
给定
$n$
和
$k$
个整数,求
$mod\ n$
加法下的群
$G$
的一个子群
$G'$
,满足
$a[1]\sim a[k-1]$
都不在群中而
$a[k]$
在群中。
$1\leqslant n\leqslant 10^{14},1\leqslant k\leqslant 250000$
Solution:
题意就是找尽量多的
$[0,n)$
内的数使得
$a[k]$
在其中而
$a[1]\sim a[k-1]$
不能由他们在模
$n$
意义下线性组合出。
考虑怎么在模
$n$
意义下线性组合出
$x$
,发现只要存在
$\gcd(x,n)$
或者他的约数再翻倍就可以了,于是把每个数和
$n$
的
$\gcd$
求出来,划掉这个数和它的约数,
$n$
的剩下的约数的所有倍数构成的集合大小就是答案。
怎么求这个有一个经典的
$2^k$
的容斥做法,但是这个题显然是不能这么做的,有一个引理,就是剩下的数中最小的数一定是所有其他的数的约数,因为如果
$x$
和
$y$
都被选中了,那么
$\gcd(x,y)$
一定要选中,因为由裴蜀定理得
$ax+by=c\times\gcd(x,y)$
有解,也就是说
$x$
和
$y$
可以在模
$n$
意义下线性组合出
$\gcd(x,y)$
,既然
$x$
和
$y$
不能线性组合出所有其他的数,那么
$\gcd(x,y)$
也一定可以,所以把这个找出来
$n/g$
就是答案。
保证
$a[k]$
在群中的做法很妙,包含
$a[k]$
其实只要包含
$\gcd(a[k],n)$
即可,就是把
$\gcd(a[k],n)$
看成
$n$
,把它分解因数再处理,这样做出来的就是在模
$\gcd(a[k],n)$
意义下
$a[1]\sim a[k-1]$
不能由他们线性组合出的答案,这个是一定包含
$\gcd(a[k],n)$
的,所以一定包含
$a[k]$
,最后统计用
$n$
除就行了。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
typedef long long ll;
ll n;
int k;
#define MAXN 250010
ll a[MAXN];
#define MAXD 10000010
ll fac[MAXD],tot = 0;
bool v[MAXD];
ll gcd(ll a,ll b){return (b == 0 ? a : gcd(b,a % b));}
int main()
{
scanf("%lld%d",&n,&k);
for(int i = 1;i <= k;++i)scanf("%lld",&a[i]);
ll g = gcd(a[k],n);
for(ll i = 1;i * i <= g;++i)
{
if(g % i == 0)
{
fac[++tot] = i;
if(i * i != g)fac[++tot] = g / i;
}
}
sort(fac + 1,fac + 1 + tot);
for(int i = 1;i < k;++i)
{
ll w = gcd(a[i],g);
int p = lower_bound(fac + 1,fac + 1 + tot,w) - fac;
v[p] = true;
}
for(int i = tot;i >= 1;--i)
{
if(!v[i])continue;
for(int j = 1;j < i;++j)
{
if(fac[i] % fac[j] == 0)
{
v[j] = true;
}
}
}
for(int i = 1;i <= tot;++i)
{
if(!v[i])
{
cout << n / fac[i] << endl;
break;
}
}
return 0;
}
In tag:
数学-裴蜀定理
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡