2018 icpc 南京区域赛-J - Prime Game Gym - 101981J

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
思路:对于第二个样例:第一个数字6的素因子2的贡献区间有
[1,1],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10] 共10个区间
第一个数字6的素因子3的贡献区间有
[1,1],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10] 共10个区间
所以当前sum = 10+10;
第二个数字7的素因子7的贡献区间有
[1,2],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10]
[2,2],[2,3],[2,4],[2,5],[2,6],[2,7],[2,8],[2,9],[2,10]
共29个区间
sum = 10+10+2
9;
第三个数字5的素因子5的贡献区间有
[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10]
[2,3],[2,4],[2,5],[2,6],[2,7],[2,8],[2,9],[2,10]
[3.3],[3,4],[3,5],[3,6],[3,7],[3,8],[3,9],[3,10];
sum = 10+10+29+8**;
第四个数字5的素因子5和第三个数的素因子相等,
之前的五已经在
[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,10]
[2,3],[2,4],[2,5],[2,6],[2,7],[2,8],[2,9],[2,10]
区间内贡献过
而当前5对[5,5],[5,6],[5,7],[5,8],[5,9],[5,10]这七个区间有贡献
所以sum+=7;
最终到n = 10,sum = 10+10+9
2+83+7+64+55+4+0+24+1+3=134
这种计数题算贡献,怎么算贡献呢?直接算有多少区间包含某一个素数的倍数。
例如,记录一下所有2的倍数的位置,3的倍数的位置,之后算有多少个区间包含2倍数的位置,这个就是2这个素数的倍数的贡献,然后算有多少个区间包含3这个素数的倍数的位置,这个就是3这个素数的贡献。
例如样例二:
2这个素数的倍数的位置有:1 5 9 10
3:1 6 7 10
5:3 4
7:2
那么2贡献的区间就有:(5-1)*1 + (9-5)*5 + (10-9)*9 + (10+1-10)*10
可以理解为:包含1不包含5的区间有多少,包含1和5不包含9的区间有多少。依次类推。

#include
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
int a[1000004];
vectorv[1000004];
int mp[1000004];
int i, j, k;
int main()
{
int n;
cin>>n;
for(int i = 1;i<=n;i++)
{
scanf("%d",&a[i]);
for(j = 2;j*j<=a[i];++j)
{
if(a[i]%j == 0)
{
v[i].push_back(j);
while(a[i]%j == 0)
a[i]/=j;
}
}//第二个for循环用来求第i个数有几个素因子,非常巧妙
if(a[i]!=1)
v[i].push_back(i);
}
for(int i = 1;i<=1000000;i++)
{
mp[i] = n+1;
}
ll ans = 0;
ll sum = 0;
for(int i = n;i>=1;i++)
{
for(j = 0;j < v[i].size();j++)
{
sum+=mp[v[i][j]] - i;
mp[v[i][j]] = i;
}
ans+=sum;
}
cout<<ans;
return 0;
}
最后附一个快速求一个数的素因子的代码
除以所有以 2 为倍数的因子
枚举以 i 为倍数为因子的整数, 此时 i 肯定不为 2.
防止 n 为一个大的素数
代码实现
#include
#include
#include
using namespace std;
void primeFactor(int n){
// 除去所有 2 的倍数的因子
while(n % 2 == 0){
printf(“2 “);
n /= 2;
}
// 经过第二步, 此时 n 一定为奇数
// 并且不存在偶数的素因子
// 所以我们可以跳过所有偶数 (i += 2)
for(int i = 3; i <= sqrt(n); i += 2){
//除去所有 i 的倍数的因子
while(n % i == 0){
printf(”%d “, i);
n /= i;
}
}
//此处为了防止是一个大于 2 的素数
if(n > 2)
printf(”%d “, n);
}
int main(){
int n;
scanf(”%d”, &n);
primeFactor(n);
return 0;
}

原文地址:https://blog.csdn.net/qq_43627087/article/details/102688819?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160613110919725222431157%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160613110919725222431157&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v28-4-102688819.pc_first_rank_v2_rank_v28&utm_term=J±+Prime+Game+Gym±+101981J&spm=1018.2118.3001.4449

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值