5.1 下饭考试1
5.1考试下饭合集
T1 序列
题目描述
HZ每周一都要举行升旗仪式,国旗班会站成一整列整齐的向前行进。
郭神作为摄像师想要选取其中一段照下来。他想让这一段中每个人的身高成等比数列,展示出最萌身高差,但他发现这个太难办到了,于是他决定放低要求,让等比数列的每两项之间可以是不连续的(例如 2,4,16……)。可他依然找不到满意的,便再次妥协,使这个等比数列可以是乱序的。
现在请在其中你找出最长的符合要求的一段,使得将这一段排序后为某个公比为q的等比数列的子序列(q∈N*,q<=1000)。
好家伙乍一看就是大暴力。。。
0.从前往后枚举位置;
1.如果之前的几项成等比数列,将比值r记录下来;
2.计算当前数字和上一位的比值jud。如果该比值与记录的比值相等(jud == r)则更新ans;
3.如果不相等,则将r更新为jud(r = jud),同时数列长度len归2;
4.(这也是最恶心的部分)当前位置数字在之前的等比数列中已经出现过了,该咋整?
再开一个f数组,f[i]表示i这个数字在等比数列中出现的位置(在原输入数列中的位置),初始值为0。遍历到当前位置的数字时,查看这个数字的f值,如果不为0,则比值r不变,返回f[i]的下一个位置,执行 3 。
听起来似乎没毛病,但有一个问题:不能直接记公比,应该记最小公比
因为这个“等比”数列可能不连续
来看正解:
0.从前往后枚举位置;
1.(预处理)(本步目的是得出两数的最小公比,若最小公比和之前的相等,则一定能构成等比数列)计算得到当前位置与上一位的比值jud,并将jud质因数分解,得到
\prod_{i=1}tot\p[i]cnt[i]\。将所有c[i]求最大公因数d,
r=\prod_{i=1}tot\p[i]cnt[i]/d\即为最小公比
开一个q数组记录每个位置的r值
(在一个等比数列中任意两个数的比值都应该是最小公比的某次方,所以求因数指数的gcd,c[i]/d后把能缩小的次方倍全部消掉,这样子能保证算出来的第二个式子无法再缩小)
2.枚举每个位置:
(1)从当前位置向后遍历;
(2)(a[i]是原数列)(本步的目的是去重)用一个set维护所有在当前等比数列里面的值。如果set.count(a[i]) == true,则跳出本次循环,清空set;
(3)(本步目的是判断数列能否向后扩展)取set中当前的最后一位(也就是最大的一个)与当前a[i]比较,若二者比值能被当前q[i]整除,则等比数列可以向后扩展;否则跳出本次循环,清空set
滑稽代码:
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int Maxn = 1e6 + 5;
int n;
ll a[Maxn];
ll cnt[Maxn], p[Maxn], q[Maxn];
ll sum = 1, ans, tot;
set<ll> s;
ll qp(ll x, ll idx){
ll res = 1, jud = x;
while(idx){
if(idx & 1) res *= jud;
idx >>= 1;
jud *= jud;
}
return res;
}
void div(ll x){
for(int i = 2; i <= 1000; i++){
if(x % i == 0){
p[++tot] = i;
cnt[i] = 0;
while(x % i == 0){
x /= i;
cnt[tot]++;
}
}
}
if(x > 1) p[++tot] = x, cnt[tot] = 1;
}
ll gcd(ll aa, ll bb){
return bb == 0? aa: gcd(bb, aa % bb);
}
bool check(ll x, ll y, ll qq){
if(x % y != 0) return false;
x /= y;
while(x % qq == 0){
x /= qq;
}
if(x == 1) return true;
else return false;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
q[i] = 1;
}
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
if(a[i] == a[i-1]) sum++, ans = max(ans, sum);
else sum = 1;
if(i >= 2){
tot = 0;
ll x = max(a[i], a[i-1]), y = min(a[i], a[i-1]);
if(x % y != 0){
continue;
}
div(x / y);
ll jud = cnt[1];
for(int j = 2; j <= tot; j++){
if(jud == 1){
break;
}
jud = gcd(jud, cnt[j]);
}
for(int j = 1; j <= tot; j++){
q[i-1] *= qp(p[j], cnt[j] / jud);
}
}
}
for(int i = 2; i <= n; i++){
if(q[i - 1]){
if(q[i - 1] == 1) continue;
s.clear();
s.insert(a[i - 1]), s.insert(a[i]);
for(ll j = i + 1; j <= n; j++){
if(s.count(a[j])){
break;
}
ll x = max(*--s.end(), a[j]);
ll y = min(*--s.end(), a[j]);
if(check(x, y, q[i - 1])){
s.insert(a[j]);
}
else break;
}
ll add = s.size();
ans = max(ans, add);
}
}
printf("%lld", ans);
return 0;
}```
浙公网安备 33010602011771号