A题: Array
原题链接:https://ac.nowcoder.com/acm/contest/33191/A
题目大意
给定大小为 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) n(1≤n≤105) 的数组 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(2≤ai≤2×105) ,满足 ∑ 1 a i ≤ 1 2 \sum \frac{1}{a_i}\le \frac{1}{2} ∑ai1≤21 。求长度为 m m m 的序列 c 0 , c 1 , . . . , c m − 1 c_0,c_1,...,c_{m-1} c0,c1,...,cm−1 。基于序列 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
∑ai1≤1 ,则题目是必然有解的。
题目的条件是
∑
1
a
i
≤
1
2
\sum \frac{1}{a_i}\le \frac{1}{2}
∑ai1≤21 ,我们不妨将
a
i
a_i
ai 改为最大的
2
k
≤
a
i
2^k\le a_i
2k≤ai (即向下取到最近的
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}
ai′1<ai2 ,故
∑
1
a
i
′
<
1
\sum \frac{1}{a_i'}<1
∑ai′1<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;
}