CF1471B 性质总结题

博客主要讨论了一道编程竞赛题目,涉及到数组操作和整除概念。机器人根据数组元素是否能被给定整数x整除来决定是否将新值添加到数组末尾。关键在于理解,即使新值能被x整除,其对总和的贡献始终是原值。博主通过创建副本数组并不断除以x来模拟过程,直到无法整除为止,从而避免了暴力模拟。代码实现使用C++,并提供了问题的解决方案。
摘要由CSDN通过智能技术生成

题目描述

您将一个长度为 nn 的数组 aa 和一个整数 xx 给了机器人。机器人的操作将会遵循以下原则:对于数组的元素进行迭代,当前的元素为 qq。如果 qq 被 xx 整除,那么机器人会将 xx 个整数 \frac{q}{x}x**q 添加到数组的末尾,然后移到下一个元素。否则,机器人停止工作。

请在机器人停止工作时确定数组所有值的总和。

输入格式

第一行包含一个整数 t(1\le t\le100)t(1≤t≤100) 输入数据的组数。

接下来对于每组数据包含一个整数 n,x(1\le n\le 100000,1\le x\le 10^9)n,x(1≤n≤100000,1≤x≤109)数组的长度和机器人的工作值。

接下来的一行包含 nn 个整数, a_1,a_2,\cdots ,a_na1,a2,⋯,a**n 表示 aa 数组。

确保所有测试用例的值 nn 的总和不超过 10 ^ 5105。


转载至繁凡大佬:https://fanfansann.blog.luogu.org/solution-cf1471b

首先第一步还是分析性质。

我们发现 q 能被 x 整除,那么在数列的末尾加上 x q x \cfrac{q}{x} xq,对答案的贡献实际上就是 x × q x = q x\times \cfrac{q}{x}=q x×xq=q。这是解题的关键。我们发现不论是第一次还是第 n 次,对答案的贡献都是 q,这样我们就不用暴力地按照题意模拟求总价值,而是直接加上 q 即可。我们发现任何一个数,哪怕本来能被 x 整除,但是把除数放到最后末尾,指针指向的时候,总有一次,会被除尽,也就是指针暂停,末尾不会再增加数字,可以开始计算最终的答案了。也就是一旦除出来的数不能被 x 整除了,就 break 退出了。因为我们要每次加上 q ,所以我们不能改变原数组,而我们需要一直除,来判断是否能继续被 x 整除,所以我们可以把数组 a copy 到数组 b

个人补充:

为什么除过x之后重新判断新添加的数能不能被再次添加,即能被再次整除后对答案的贡献还是q。是因为,我们上一次得到的新的元素一共是x个,每一个是 q x \cfrac{q}{x} xq q x \cfrac{q}{x} xq还能被x整除,那么得到的就是 q x ∗ x \cfrac{q}{x *x} xxq,一共有x个 q x \cfrac{q}{x} xq能被整除添加,对答案的贡献就是 q x ∗ x ∗ x ∗ x = q \cfrac{q}{x*x}*x*x=q xxqxx=q

// Problem: B. Strange List
// Contest: Codeforces - Codeforces Round #694 (Div. 2)
// URL: https://codeforces.com/contest/1471/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// Code by: ING__
// 
// Powered by CP Editor (https://cpeditor.org)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <sstream>
#define ll long long
#define re return
#define Endl "\n"
#define endl "\n"

using namespace std;

typedef pair<int, int> PII;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int T;
int n, x;
int a[100000 + 10];
int b[100000 + 10];

int main(){
	cin >> T;
	while(T--){
		cin >> n >> x;
		
		ll summ = 0;
		
		for(int i = 1; i <= n; i++){
			scanf("%d", a + i);
			b[i] = a[i];
			summ += a[i];
		}
		
		int f = 1;
		while(1){
			for(int i = 1; i <= n; i++){
				if(a[i] % x == 0){
					summ += b[i];
					a[i] /= x;
				}
				else{
					f = 0;
					break;
				}
			}
			if(!f){
				break;
			}
		}
		cout << summ << endl;
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值