本文章为一些非常简单数论题的题解。
CF762A k-th divisor
题意:找到 的第 小因子。不存在输出 。
数据范围: ,。
题解与代码
题解:注意到因子都是成对出现的。因此枚举 暴力判断即可。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
long long n,k,cnt=0,exist=0;
void yzmain()
{
scanf("%lld%lld",&n,&k);
for(long long i=1;i*i<=n;i++)//暴力判断
if(n%i==0)
{
cnt++;if(i*i==n) exist=1;//exist 判断是否存在两个相同数相乘为n
if(cnt==k)
{
printf("%lld\n",i);
return;
}
}
cnt*=2;cnt-=exist;//算出因子数
if(cnt<k)//不存在输出 -1
{
printf("-1\n");
return;
}
for(long long i=1;i*i<=n;i++)//接着暴力判断
if(n%(n/i)==0)
{
if(cnt==k)
{
printf("%lld\n",n/i);
return;
}
cnt--;
}
}
return;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
_yz::yzmain();
return 0;
}
CF776B Sherlock and his girlfriend
题意:有 个点,编号 ,给这些点染色,要求若 是 的质因子,则 和 的颜色不同,求一种颜色数最少的方案。
数据范围:。
题解与代码
题解:注意到质因子关系是二分图,一边是质数,一边是合数。把质数都染成 ,合数都染成 即可。因此当 时,颜色数最少为 ,否则为 。惊不惊喜,意不意外?
代码:
#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
int n;
int check(int x)
{
for(int i=2;i*i<=x;i++)
if(x%i==0) return 2;
return 1;
}
void yzmain()
{
scanf("%d",&n);
if(n==1)
{
printf("1\n1");
return;
}
if(n==2)
{
printf("1\n1 1");
return;
}
printf("2\n");
for(int i=2;i<=n+1;i++)
printf("%d ",check(i));
return;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
_yz::yzmain();
return 0;
}
CF664A Complicated GCD
题意:给定整数 ,,求 。
数据范围:。
题解与代码
题解:
设 表示 的最大公约数。
注意到,。故当 时,输出 ,否则输出 。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
string a,b;
void yzmain()
{
cin>>a>>b;
if(a!=b) printf("1\n");
else cout<<a;
return;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
_yz::yzmain();
return 0;
}
CF757B Bash’s Big Day
题意:给定 个正整数 。求一个子集 ,满足 ,同时 尽可能大。
数据范围:。
题解与代码
题解:,说明存在一个正整数 ,满足 整除 内的所有元素。枚举 ,以桶的方式统计答案。设 ,时间复杂度为 。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
int n,a[100000+5],ans=1,mx=0,tmp;
int check(int k)
{
int ret=0;
for(int i=k;i<=mx;i+=k)
ret+=a[i];
return ret;
}
void yzmain()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&tmp),mx=max(mx,tmp),a[tmp]++;
for(int i=2;i<=mx;i++) ans=max(ans,check(i));
printf("%d\n",ans);
return;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
_yz::yzmain();
return 0;
}
CF632D Longest Subsequence
题意:给出包含 个数的数列 ,要求选出尽可能多的数,满足它们的最小公倍数不大于 。允许不选,此时最小公倍数为 。输出这个最小公倍数,选出数的个数,以及这些数在数列中的位置。
数据范围:,。
题解与代码
题解:
首先,注意到 ,所以若 ,则 可直接舍弃。好,我们成功地把数据范围由 优化到 了。
之后,如果数 的约数集合为 ,则集合 的最小公倍数一定小于等于 。好,我们成功地把问题转化为求约数个数了。
我们可以枚举 ,求数列 中有多少数可整除 ,求个最大值。不过这样时间复杂度为 ,超时。我们可以把这个过程转换一下,枚举 ,看 能为 中的哪些数做贡献。很明显, 可为所有为 的倍数的数做贡献(当然要小于 )。好,我们成功地降低时间复杂度为 了。
此算法可通过本题。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
const int N=1000000+10;
int a[N],num[N],n,m,ans[N],v[N],lcm=1,cnt=0;
void yzmain()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
if(a[i]<=m) num[a[i]]++;//忽略大于m的数,使用桶统计数的个数
}
for(int i=1;i<=n;i++)
{
if(a[i]>m || v[a[i]]) continue;//数大于m || 重复数
for(int j=1;j*a[i]<=m;j++)
ans[a[i]*j]+=num[a[i]];//统计贡献
v[a[i]]=1;//去重
}
for(int i=1;i<=m;i++)
if(ans[i]>cnt) lcm=i,cnt=ans[i];//保证是**最小**公倍数
printf("%d %d\n",lcm,cnt);
for(int i=1;i<=n;i++)
if(lcm%a[i]==0) printf("%d ",i);
return;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
_yz::yzmain();
return 0;
}
P1445 [Violet]樱花
题意:给定 ,求方程 的正整数解的组数,答案对 取模。。
点击查看题解
题解:看着这个式子,什么玩意!不过可以对式子进行变形:
发现,每一组 和 都唯一对应着 的因子。
所以,此题转化为,求 的因子个数。
算术基本定理:。 为质数。这样的分解是唯一的。
因数个数:。可以推出 。排列组合和乘法原理可证。
附加题:求 。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace name
{
typedef long long ll;
const ll mod=1000000007,N=1000000+10;
ll n,prime[N],p[N],e[N],ans=1,cnt=0;
void getPrime(ll n)
{
for(ll i=2;i<=n;i++)
{
if(!p[i]) prime[++cnt]=i,p[i]=i;
for(ll j=1;j<=cnt;j++)
{
if(prime[j]>p[i]||prime[j]>n/i) break;
// 保证 prime_j 是最小质因数 || 不要超过 n
p[i*prime[j]]=prime[j];
}
}
return;
}
void main()
{
scanf("%lld",&n);
getPrime(n);
for(ll i=1;i<=n;i++)
{
for(ll j=i;j>=2;j/=p[j])
e[p[j]]++;
}
for(ll i=2;i<=n;i++)
ans=(ans*(e[i]*2%mod+1))%mod;
printf("%lld\n",ans);
return;
}
}
int main()
{
name::main();
return 0;
}
P1072 [NOIP2009 提高组] Hankson 的趣味题
题意:已知正整数 ,,,,设某未知正整数 满足:
和 的最大公约数是 ;
和 的最小公倍数是 。
求解满足条件的 的个数。保证有 , 且 ,。
点击查看题解
题解:
- (显然 / 反证)。
- 。
现在应用这两个结论。
- 。
- 。
输入数据保证 能被 整除, 能被 整除。故枚举 ( 因子) 即可。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace name
{
typedef long long ll;
ll a0,a1,b0,b1,ans;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll check(ll x)
{
if(x%a1!=0) return 0;
if(gcd(x/a1,a0/a1)!=1) return 0;
if(gcd(b1/x,b1/b0)!=1) return 0;
return 1;
}
void main()
{
ll T;
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1);
ans=0;
for(ll i=1;i*i<=b1;i++)
{
if(b1%i) continue;
if(check(i)) ans++;
ll j=b1/i;
if(i==j) break;
if(check(j)) ans++;
}
printf("%lld\n",ans);
}
return;
}
}
int main()
{
name::main();
return 0;
}
P3197 [HNOI2008]越狱
题意
监狱有 个房间,每个房间关押一个犯人,有 种宗教,每个犯人会信仰其中一种。如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱。
答案对 取模。
对于 的数据,保证 ,。
点击查看题解
题解
发生越狱数 总数 不发生越狱数。
总数:每个房间有 种宗教可选,故为 。
不发生越狱数:第一个房间信什么都行,第二个不能信第一个信的那个,第三个不能信第二个信的那个……故为 。
所以答案为:。
代码
#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
typedef long long ll;
const ll mod=100003;
ll n,m,ans=0;
ll pow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b%2) ret=ret*a%mod;
a=a*a%mod; b/=2;
}
return ret;
}
void main()
{
scanf("%lld%lld",&m,&n);
ans=pow(m,n);
ans=((ans-(m*pow(m-1,n-1)))%mod+mod)%mod;
printf("%lld\n",ans);
return;
}
}
int main()
{
_yz::main();
return 0;
}
小白鼠保护协会的孤注一掷
2023-08-14
不想改格式。
题目背景
邪恶的 xytz 又双叒要拿小白鼠做实验了,身为小白鼠保护协会的你要尽自己最大可能去保护它们。
题目描述
xytz 有 瓶药,有一瓶过期了(过期药有毒),需要用多只小白鼠来测试哪一瓶药过期,过期药 24h 毒效发作,问:保证在时间最短的前提下,最少用多少只小白鼠。
输入格式
输入一个正整数 ,表示需要测试多少瓶药。
输出格式
输出一个正整数 ,表示在时间最短的前提下,最少用多少只小白鼠。
样例 #1
样例输入 #1
100
样例输出 #1
7
提示
对于 的数据,;
对于 的数据,。
题解
信息论。把 瓶药编号,如果其编号在二进制下第 位为 ,就让第 个小白鼠吃。这样看死亡情况即可推知是哪瓶药有毒。
本文作者:Yurchiu
本文链接:https://yz-hs.github.io/e4b4986bb6ee/
版权声明:本博客中所有原创文章除特别声明外,均允许规范转载,转载请注明出处。所有非原创文章,按照原作者要求转载。