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;
}```
posted @ 2021-05-05 10:12  Na_Hs  阅读(89)  评论(0)    收藏  举报