“蔚来杯“2022牛客暑期多校训练营6 A题: Array

A题: Array

原题链接:https://ac.nowcoder.com/acm/contest/33191/A

题目大意

给定大小为 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) n(1n105) 的数组 a 1 , a 2 , . . . , a n ( 2 ≤ a i ≤ 2 × 1 0 5 ) a_1,a_2,...,a_n(2\le a_i\le 2\times 10^5) a1,a2,...,an(2ai2×105) ,满足 ∑ 1 a i ≤ 1 2 \sum \frac{1}{a_i}\le \frac{1}{2} ai121 。求长度为 m m m 的序列 c 0 , c 1 , . . . , c m − 1 c_0,c_1,...,c_{m-1} c0,c1,...,cm1 。基于序列 c c c ,可以生成无限长的序列 b b b ,满足 b i = c i m o d    m b_i=c_{i \mod m} bi=cimodm b b b 必须满足其中任意连续 a i a_i ai 个数中,必有一个值为 i i i

注意 a a a 序列下标从 1 1 1 开始, b , c b,c b,c 下标从 0 0 0 开始。 m ∈ [ 1 , 1 0 6 ] m\in [1,10^6] m[1,106] 可以任意选择。

题解

充分观察和利用题目条件!
显然,若 ∑ 1 a i ≤ 1 \sum \frac{1}{a_i}\le 1 ai11 ,则题目是必然有解的。
题目的条件是 ∑ 1 a i ≤ 1 2 \sum \frac{1}{a_i}\le \frac{1}{2} ai121 ,我们不妨将 a i a_i ai 改为最大的 2 k ≤ a i 2^k\le a_i 2kai (即向下取到最近的 2 2 2 的整数次幂),此时新的 a i ′ > a i 2 a_i'>\frac{a_i}{2} ai>2ai ,即 1 a i ′ < 2 a i \frac{1}{a_i'}<\frac{2}{a_i} ai1<ai2 ,故 ∑ 1 a i ′ < 1 \sum \frac{1}{a_i'}<1 ai1<1 仍有解。
此时 l c m { a 1 ′ , a 2 ′ , . . . , a n ′ } lcm\{a_1',a_2',...,a_n'\} lcm{a1,a2,...,an} 肯定为一个小于 1 0 6 10^6 106 2 2 2 的整数次幂,我们不妨取 m = 2 19 < 1 0 6 m=2^{19}<10^6 m=219<106
根据 a i ′ a_i' ai 从小到大,对于每个 i i i 每隔 a i a_i ai 插入一个值,此时因为 m m m a i ′ a_i' ai 的倍数,所以只要序列 c c c 满足要求,由 c c c 的重复周期得到的序列 b b b 也一定满足。
(注意 a i ′ a_i' ai 要按照从小到大,否则可能出现插入一个 i i i 时,序列 c c c 最前面的一段已经被占满的情况)
暴力构造即可。

参考代码

#include<bits/stdc++.h>
using namespace std;

template<class T>inline void read(T&x){
	char c,last=' ';
	while(!isdigit(c=getchar()))last=c;
	x=c^48;
	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
	if(last=='-')x=-x;
}

#define P pair<int,int> 
const int MAXN=1e6+5;
int n;
int a[MAXN];
P p[MAXN];
int ans[MAXN];

int main()
{
	read(n);
	for(int i=1;i<=n;++i){
		read(a[i]);
		while(a[i]&(a[i]-1))a[i]-=(a[i]&-a[i]);//(a[i]&(a[i]-1))判断是否为2的整数次幂,(a[i]&-a[i])取出当前二进制中最低的1
		p[i]=P(a[i],i);
	}
	sort(p+1,p+n+1);
	int lim=1<<19;
	for(int i=1,j=1;i<=n;++i){
		while(ans[j])++j;//跳过已经使用的位
		for(int k=j;k<=lim;k+=p[i].first)ans[k]=p[i].second;
	}
	for(int i=1;i<=lim;++i)if(!ans[i])ans[i]=1;//补足空位
	cout<<lim<<'\n';
	for(int i=1;i<=lim;++i)cout<<ans[i]<<" \n"[i==lim];
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值