题目描述
大家都知道,卡德加是个神奇的法师。 有一天,他发现了一种可以作用在埃匹希斯水晶上的魔法:在左右两个祭坛上放一定量的水晶,然后施放一个法术,左边一堆的水晶数量会变成原来两个祭坛上水晶之和,右边一堆会变成两个祭坛上水晶数量之差。
卡德加现在有两堆水晶,分别有 A 个和 B 个。他打算集中精神连续 释放 N次法术,但不知道最后能拿到多少水晶,于是他找到了要塞指挥官(就是你了)。
输入格式
三个整数 A, B, N ,表示祭坛上刚开始的水晶数,和法术的释放次数。
输出格式
两个数,祭坛上最后的水晶数。输出模 (10e8 + 7)。
样例数据
input
1 2 3
output
6 2
数据规模与约定
50%: N ≤ 10e6 。 100%: A, B ≤ 10e8 , N ≤ 10e18 。
时间限制:1s
空间限制:256MB
简单的思考本题,就会发现有一个很简单的规律:
第一堆 | 第二堆 |
---|---|
A | B |
A+B | A-B |
2*A | 2*B |
… | … |
2n/2*A | 2n/2*B |
每操作两次,左边的水晶数和右边的水晶数就会翻一倍。
那么用快速乘和快速幂做2的整次方就可以解决这个问题。如果n为奇数,那就先手动操作一个,再乘2的整次方。
#include
using namespace std;
long long A,B,n,ansa,ansb;
const long long P=10e8+7;
inline void input(void)
{
scanf("%lld%lld%lld",&A,&B,&n);
if(A<B)swap(A,B);
}
inline long long Max(long long a,long long b){return a>b?a:b;}
inline long long Min(long long a,long long b){return a<b?a:b;}
inline long long mul(long long a,long long b)
{
long long result=0;
while(b>0)
{
if(b&1)result+=a,result%=P;
b>>=1;
a+=a,a%=P;
}
return result;
}
inline long long power(long long a,long long b)
{
long long result=1;
while(b>0)
{
if(b&1)result=mul(result,a);
b>>=1;
a=mul(a,a);
}
return result;
}
inline void work(void)
{
if(n%2==0)ansa=mul(A%P,power(2,n/2)%P),ansb=mul(B%P,power(2,n/2)%P);
else ansa=mul(A%P+B%P,power(2,n/2)%P),ansb=mul(A%P-B%P,power(2,n/2)%P);
}
int main(void)
{
freopen("apexis.in","r",stdin);
freopen("apexis.out","w",stdout);
input();
work();
printf("%lld %lld\n",ansa%P,ansb%P);
return 0;
}
题目描述
你的要塞⾥有 N 名随从,每名随从有⼀个战⽃⼒值 Ai ,不同随从的战⽃⼒可以相同,且永远不超过 N 。⼀个要塞任务需要恰好 M 个随从参与。
要塞任务的奖励取决于随从们配合的程度。(显⽽易见地),M 个随 从的联合战⽃⼒ A 为它们战⽃⼒的最大公约数,⽽任务的奖励分数定义为ϕ(A)。
求最大可能的奖励分数。
输入格式
本题有多组数据,第⼀⾏为数据组数 T 。 接下来每组数据有两⾏,第⼀⾏两个整数 N, M ,第⼆⾏ N 个整数 Ai 。
输出格式
一行,一个整数,表示答案。
样例数据
input
1
5 2
1 4 6 9 12
output
2
数据规模与约定
20%:N M ≤ 10e5 。 60%:N, M, Ai ≤ 100。 100%:N, M, Ai ≤ 100000,T ≤ 10。
时间限制:1s
空间限制:256MB
我们可以先利用线性筛法预处理出1~n的欧拉函数。其具体步骤不再详解,可以参照以前数论博客。
有了欧拉函数后,我们的问题就转变为了一个数A,他是数列中至少m个数的最大公约数,且使得 ϕ ( A ) \phi(A) ϕ(A)最大。
那么思维的转换就在这个地方,我们其实直接枚举A就可以了。怎么判断它至少是m个数的最大公约数呢?我们先用桶记录每一个数出现的次数 c n t [ i ] cnt[i] cnt[i],当枚举到一个数 A ′ A' A′时,显然 A ′ , 2 A ′ , 3 A ′ , . . . , k A ′ A',2A',3A',...,kA' A′,2A′,3A′,...,kA′这些数的最大公约数是 A ′ A' A′,那么我们累加 c n t cnt cnt数组,得到 Σ i = 1 i ∗ A ′ ≤ m a x { a i } c n t [ i ∗ A ′ ] \Sigma_{i=1}^{i*A'≤max\{a_i\}}cnt[i*A'] Σi=1i∗A′≤max{ai}cnt[i∗A′]的值,就可以判断了,如果这个值大于m,显然他是符合要求的,我们可以利用预处理的欧拉函数尝试更新答案,反之,跳过就可以了。
#include
using namespace std;
#define mset(k) memset(k,0,sizeof(k))
int n,m,Combatpower[100080]={},cnt[100080]={},Max=-1,ans=-1;
int phi[100080]={},prime[100080]={},flag[100080]={},Cnt=0;
inline void input(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&Combatpower[i]),cnt[Combatpower[i]]++;
Max=max(Max,Combatpower[i]);
}
}
inline void eular()
{
for(int i=2;i<=n;i++)
{
if(!flag[i]){prime[++Cnt]=i;phi[i]=i-1;}
for(int j=1;j<=Cnt;j++)
{
if(prime[j]*i>n)break;
flag[prime[j]*i]=true;
if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
inline void solve(void)
{
for(int i=1;i<=Max;i++)
{
if(ans>=phi[i])continue;//优化:如果符合要求也更新不了答案,直接跳过即可
int t=0;
for(int j=i;j<=Max;j+=i)
{
if(cnt[j])t+=cnt[j];
if(t>=m)break;//优化:如果已经符合要求,就不用再统计了
}
if(t>=m)ans=max(ans,phi[i]);
}
printf("%d\n",ans);
}
int main(void)
{
freopen("quest.in","r",stdin);
freopen("quest.out","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
mset(flag);mset(prime);mset(phi);mset(cnt);mset(Combatpower);
Cnt=0;Max=ans=-1;
input();
eular();
solve();
}
return 0;
}
题目描述
奶牛们有一个习惯,那就是根据自己的编号选择床号。如果一头奶牛编号是a,并且有0…k-1一共k张床,那么她就会选择a mod k号床作为她睡觉的地点。显然,2头牛不能睡在一张床上。那么给出一些奶牛的编号,请你为她们准备一间卧室,使得里面的床的个数最少。
输入格式
第一行是奶牛的个数n(1<=n<=5000);第2到第n+1行是每头奶牛的编号Si(1<=Si<=1000000)。
输出格式
仅一行,是最少的床的数目。
input
5
4
6
9
10
13
output
8
数据规模与约定
1s
未知
时间限制:1s
空间限制:256MB
题目要求我们求解一个k,使得任何一个 a i % k a_i \% k ai%k各不相同。那么,显然有的是:对于任意 a i , a j a_i,a_j ai,aj, k k k不能作为 a i − a j a_i-a_j ai−aj的因数,否则,他们一定同余。那么,我们可以用桶标记任意两个数的差, d i f [ i ] = t r u e dif[i]=true dif[i]=true代表存在两个数的差为i。那么我们可以直接枚举从小到大k,并判断 d i f [ k ] dif[k] dif[k]是否为假,如果是假,继续判断 d i f [ k ] dif[k] dif[k]的整数倍是否为假,如果都为假,那就说明这个k符合要求,直接输出即可。
#include
using namespace std;
int n,num[5080]={},dif[1000080]={},Max=-1;
inline void input(void)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&num[i]),Max=max(Max,num[i]);
}
inline void Marking(void)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dif[abs(num[i]-num[j])]=true;
}
}
}
inline void Find(void)
{
for(int i=n;i<=Max;i++)
{
if(!dif[i])
{
for(int j=i;j<=Max;j+=i)
{
if(dif[j]==true)
{
dif[i]=true;
}
}
if(!dif[i])
{
printf("%d\n",i);
break;
}
}
}
}
int main(void)
{
freopen("bed.in","r",stdin);
freopen("bed.out","w",stdout);
input();
Marking();
Find();
return 0;
}
题目大意
在进入矿洞N久之后,Abigail 已经取得了一大堆各种各样的矿石,并将这些矿石熔化一个个装进了瓶子里了.
这些瓶子都有一个属性Ai,这个属性Ai的所有因数表示了这个瓶子内装的液体的特性.当两个瓶子i和j中的液体要混合时,它们混合的液体属性g就是Ai和Aj都具有的最大液体特性,即g=gcd(Ai,Aj).
现在 Abigail 经过了十分劳累的冶炼,摊在地上突然想到了一个神奇的问题,如果把任意两只瓶子混合起来,得到的液体属性为gi有多少种可能呢.
注意,对于两个编号为i,j(i≠j),(i,j)和(j,i))算成两种不同的方案.
输入格式
输入第1行包括一个整数n,表示 Abigail 得到了n瓶溶液.
接下来n行,每行一个正整数Ai,表示第i瓶液体的属性.
接下来1行,包括一个整数 m,表示询问的 gi的数量.
接下来m行,每行一个正整数 gi,表示询问.
输出格式
输出包括 m行,第i行一个正整数表示第i个询问的答案.
数据范围
对于100%的数据: 1≤Ai1≤Ai 1≤m≤2n
首先,我们需要用桶记录每一个数出现的次数,即 c n t [ i ] cnt[i] cnt[i]代表 A A A中 i i i出现的次数。那么,我们就可以求出每一个数作为别的数的因子的次数,即 n u m [ i ] = Σ j = 1 i ∗ j ≤ m a x { A i } c n t [ i ∗ j ] num[i]=\Sigma_{j=1}^{i*j≤max\{A_i\}}cnt[i*j] num[i]=Σj=1i∗j≤max{Ai}cnt[i∗j]。由乘法原理可得:每一个数做为其他数对的公约数的次数 N [ i ] = n u m [ i ] ∗ ( n u m [ i ] − 1 ) N[i]=num[i]*(num[i]-1) N[i]=num[i]∗(num[i]−1),但是,这只是公约数,我们要求的是每一个数作为其他数对的最大公约数的次数,设i作为其他数对的最大公约数的次数为 c [ i ] c[i] c[i],那么 c [ i ] c[i] c[i]其实等于i作为其他数对的公约数的次数减掉i整数倍作为其他数对的最大公约数的次数,即 c [ i ] = N [ i ] − Σ j = 2 i ∗ j ≤ m a x { A i } c [ i ∗ j ] c[i]=N[i]-\Sigma_{j=2}^{i*j≤max\{A_i\}}c[i*j] c[i]=N[i]−Σj=2i∗j≤max{Ai}c[i∗j]。那么,它询问 g g g,我们输出 c [ g ] c[g] c[g]即可。
#include
using namespace std;
#define mset(name,value) memset(name,value,sizeof(name))
const long long INF=0x3f3f3f3f;
inline void read(long long &k)
{
long long x=0,w=0;char ch;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
k=(w?-x:x);return;
}
long long n,m,a[1000080]={},cnt[1000080]={},num[1000080]={},c[1000080]={},N[1000080]={},Max=-1;
inline void input(void)
{
read(n);
for(long long i=1;i<=n;i++)
{
read(a[i]);cnt[a[i]]++;
Max=max(Max,a[i]);
}
for(long long i=1;i<=Max;i++)
{
for(long long j=i;j<=Max;j+=i)
{
num[i]+=cnt[j];
}
}
for(long long i=1;i<=Max;i++)N[i]=num[i]*(num[i]-1);
for(long long i=Max;i>=1;i--)
{
c[i]=N[i];
for(long long j=i+i;j<=Max;j+=i)
{
c[i]-=c[j];
}
}
read(m);
}
inline void solve(void)
{
for(long long i=1;i<=m;i++)
{
long long g;read(g);
printf("%lld\n",c[g]);
}
}
int main(void)
{
freopen("fuse.in","r",stdin);
freopen("fuse.out","w",stdout);
input();
solve();
return 0;
}