题目链接:https://www.cnblogs.com/Juve/articles/11186805.html(密码是我的一个oj用户名)

题解:

这题我考试打的暴力,只有5分。

一开始理解错题意了,以为2,4,32这类不符合,于是有了下面的代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define MAXN 100005
#define re register
#define in inline
using namespace std;
in ll read(){
re ll x=;char ch=getchar();
while(ch<''||ch>''){ch=getchar();}
while(ch>=''&&ch<=''){
x=(x<<)+(x<<)+ch-'';
ch=getchar();
}
return x;
}
ll n,a[MAXN],tot=,ans=;
in ll max(re ll a,re ll b){
return a>b?a:b;
}
in ll min(re ll a,re ll b){
return a<b?a:b;
}
in bool judge(re ll x,re ll y){
re ll num=,q;
re ll b[MAXN];
for(re ll i=x;i<=y;i++){
b[++num]=a[i];
}
sort(b+,b+num+);
//cout<<b[1]<<' '<<b[2]<<endl;
//if(b[2]==b[1]) return 0;
q=b[]/b[];
for(re ll i=;i<=num;i++){
if(b[i]%b[i-]!=) return ;
if(b[i]==b[i-]) return ;
if(b[i]/b[i-]!=q) return ;
}
return ;
}
signed main(){
//freopen("test.in","r",stdin);
n=read();
for(re ll i=;i<=n;i++){
a[i]=read();
if(a[i]==) ans=;
if(a[i]==a[i-]) tot++;
else{
ans=max(tot,ans);
tot=;
}
}
if(ans==n){
printf("%lld\n",ans);
return ;
}
for(re ll i=;i<=n;i++){
if(!a[i]||!a[i+]){
continue;
}
for(re ll j=i+;j<=n;j++){
//cout<<j<<endl;
if(judge(i,j)){
//cout<<i<<' '<<j<<endl;
tot=j-i+;
ans=max(ans,tot);
//cout<<tot<<endl;
}
else{
ans=max(ans,tot);
}
}
}
ans=max(ans,tot);
printf("%lld\n",ans);
return ;
}

5分

考完试看正解,没看懂,于是开始更改我的暴力思路

设dp[q][i]表示公比为q,以i结尾能组成题目中序列的个数

我们先求出数列的max和min,得到q的范围

首先枚举q,之后枚举整个数列,对与每个a[i]和a[i-1],如果max(a[i],a[i-1])%min(a[i],a[i-1]),

那么枚举q的指数qp,如果min(a[i],a[i-1])*qp=max(a[i],a[i-1]),那么从i向前dp[q][i-1]中判重,若没有重复,那么dp[q][i]=dp[q][i-1]+1;

判重是防止以下情况:4,2,4;

4在前面出现过一次了,所以dp[q][3]=2而不是3;

具体做法:

for(ll p=;p<=;p++){
ll Q=power(q,p);
if(Q>maxx) break;
if(mi*Q==ma){
bool flag=;
for(ll k=;k<=dp[q][i-];k++){
if(a[i]==a[i-k]){
dp[q][i]=k;flag=;
ans=max(ans,dp[q][i]);
//cout<<ans<<' '<<dp[q][i]<<' '<<q<<' '<<i<<endl;
break;
}
}
if(!flag){
dp[q][i]=dp[q][i-]+;
ans=max(ans,dp[q][i]);
//cout<<ans<<' '<<dp[q][i]<<' '<<q<<' '<<i<<endl;
}
break;
}
}

细节的地方包括判断0以及公比是一的情况,随时更新ans

Ps:因为这道题的数据实在是不好造,所以最后公比最大不会很大,博主试验过了,公比最大是10

于是我们快乐地A掉了这道题

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define MAXN 100005
#define re register
#define in inline
using namespace std;
in ll read(){
re ll x=;char ch=getchar();
while(ch<''||ch>''){ch=getchar();}
while(ch>=''&&ch<=''){
x=(x<<)+(x<<)+ch-'';
ch=getchar();
}
return x;
}
ll n,a[MAXN],tot=,ans=,maxx=,minn=9e18;
ll max_q,dp[][MAXN];//dp[q][i]表示公比为q,以一下标i结尾的序列最大能得到多长的等比序列
in ll max(re ll a,re ll b){
return a>b?a:b;
}
in ll min(re ll a,re ll b){
return a<b?a:b;
}
ll power(ll a,ll b){
ll ans=;
for(;b;b>>=){
if(b&) ans=(ll)ans*a;
a=(ll)a*a;
}
return ans;
}
signed main(){
n=read();
//cout<<n<<endl;
for(re ll i=;i<=n;i++){
a[i]=read();
maxx=max(a[i],maxx);
minn=min(a[i],minn);
if(a[i]==){
ans=max(ans,tot);
tot=;
continue;
}
if(a[i]==a[i-]){
tot++;
ans=max(ans,tot);
}
else{
ans=max(ans,tot);
tot=;
}
//cout<<tot<<endl;
}
// cout<<ans<<endl;
if(minn==) minn=;
max_q=min(,maxx/minn);
//cout<<max_q<<endl;
for(ll q=;q<=max_q;q++){//枚举公比
dp[q][]=;
if(a[]==) dp[q][]=;
else dp[q][]=;
for(ll i=;i<=n;i++){
if(a[i]==){
dp[q][i]=;
continue;
}
ll ma=max(a[i],a[i-]),mi=min(a[i],a[i-]);
//cout<<i<<endl;
//cout<<ma<<' '<<mi<<endl;
if(ma==mi){
dp[q][i]=;
continue;
}
if(mi==||ma%mi!=){
dp[q][i]=;
//cout<<ans<<' '<<dp[q][i]<<' '<<q<<' '<<i<<endl;
}else{
for(ll p=;p<=;p++){
ll Q=power(q,p);
if(Q>maxx) break;
if(mi*Q==ma){
bool flag=;
for(ll k=;k<=dp[q][i-];k++){
if(a[i]==a[i-k]){
dp[q][i]=k;flag=;
ans=max(ans,dp[q][i]);
//cout<<ans<<' '<<dp[q][i]<<' '<<q<<' '<<i<<endl;
break;
}
}
if(!flag){
dp[q][i]=dp[q][i-]+;
ans=max(ans,dp[q][i]);
//cout<<ans<<' '<<dp[q][i]<<' '<<q<<' '<<i<<endl;
}
break;
}
}
}
}
}
//for(ll i=1;i<=max_q;i++)
// for(ll j=1;j<=n;j++)
// cout<<dp[i][j]<<' '<<i<<' '<<j<<endl;
printf("%lld\n",ans);
return ;
}

但其实这还不是正解

正解非常神仙:

因为选出的一段是一个等比序列的子序列,我们分为两种情况:
1. q=1,相当于找一个最长每个数都相等的子串,这个扫一遍就行了。
2. q!=1,那么这个序列最长只有$log_{2}n$,那么我们可以枚举开头,不妨设开始的两个数为 a[i]和 a[i+1],
其中比较大的一个为 x,另一个 y。
(1) 首先要满足 x%y=0
(2) 让 z=$\frac{x}{y}$,然后把 z 质因数分解,z=$p_{1}^{q_2}$×$p_{1}^{q_2}$×$p_{1}^{q_2}$......,设 g=gcd(q1,q2,q3...),那么当前序
列的最小公比就是 $p_{1}^{\frac{q_{1}}{g}}$×$p_{2}^{\frac{q_{2}}{h}}$×......
(3) 我们找到最小公比后,每当往后加一个数,判断它与前边的数的比是否是最小公比的整次幂,
不是的话就说明不能再加了。
(4) 还有一个要求就是这个序列里不能有重复的数,这个东西用 set 判断就行了。
复杂度 O($nlog_{2}^{2}n$);

正解代码:

 #include<bits/stdc++.h>
using namespace std;
const long long L=<<|;
char buffer[L],*S,*TT;
#define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,L,stdin),S==TT))?EOF:*S++)
long long n;
long long data[],ans=,z[],q[],tot=;
long long p[],c[];
set<long long> s;
inline long long read()
{
register long long a=,b=;char ch=getchar();
while(ch<''||ch>'')b=(ch=='-')?-:,ch=getchar();
while(ch>=''&&ch<='')a=(a<<)+(a<<)+(ch^),ch=getchar();
return a*b;
}
inline long long qpow(register long long x,register long long y)
{
register long long ans=;
while(y)
{
if(y&)ans*=x;
x*=x;
y>>=;
}
return ans;
}
inline long long gcd(register long long x,register long long y)
{
register long long i,j;
if(x==)return y;
if(y==)return x;
for(i=;==(x&);++i)x>>=;
for(j=;==(y&);++j)y>>=;
if(j<i)i=j;
while()
{
if(x<y)x^=y,y^=x,x^=y;
if(==(x-=y))return y<<i;
while(==(x&))x>>=;
}
}
inline void divide(register long long x)
{
tot=;
for(register long long i=;i<=min((long long),(long long)sqrt(x));i++)
if(!(x%i))
{
p[++tot]=i;c[tot]=;
while(!(x%i))x/=i,c[tot]++;
}
if(x>)p[++tot]=x,c[tot]=;
}
inline bool jud(register long long x,register long long y,register long long q)
{
if(x%y)return ;
x/=y;
while(x%q==)x/=q;
if(x!=)return ;
return ;
}
signed main()
{
n=read();
register long long sum=;
for(register long long i=;i<=n;++i)q[i]=;
for(register long long i=;i<=n;++i)
{
data[i]=read();
if(data[i]==data[i-])++sum;
else sum=;
ans=max(ans,sum);
if(i>=)
{
register long long x=max(data[i],data[i-]);
register long long y=min(data[i],data[i-]);
if(x%y)continue;
register long long d=x/y;
divide(d);
register long long g=c[];
for(register long long m=;m<=tot;++m)
{
if(g==)break;
g=gcd(g,c[m]);
}
for(register long long l=;l<=tot;++l)
{
q[i-]*=qpow(p[l],c[l]/g);
if(q[i-]>)
{
q[i-]=;
break;
}
}
}
}
for(register long long i=;i<=n;i++)
if(q[i-])
{
if(q[i-]==)continue;
s.clear();
s.insert(data[i-]),s.insert(data[i]);
for(register long long j=i+;j<=n;j++)
{
if(s.count(data[j]))break;
register long long x=max(*--s.end(),data[j]);
register long long y=min(*--s.end(),data[j]);
if(jud(x,y,q[i-]))s.insert(data[j]);
else break;
}
register long long mm=s.size();
ans=max(ans,mm);
}
printf("%lld",ans);
}

非常感谢soul提供的代码,soul有素质有情怀有状态有节操%拜

HZOI2019序列的更多相关文章

  1. 【夯实PHP基础】UML序列图总结

    原文地址 序列图主要用于展示对象之间交互的顺序. 序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸.横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色 ...

  2. Windows10-UWP中设备序列显示不同XAML的三种方式[3]

    阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universa ...

  3. 软件工程里的UML序列图的概念和总结

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 软件工程的一般开发过程:愿景分析.业务建模,需求分析,健壮性设计,关键设计,最终设计,实现…… 时序图也叫序列图(交互图),属于软件 ...

  4. python序列,字典备忘

    初识python备忘: 序列:列表,字符串,元组len(d),d[id],del d[id],data in d函数:cmp(x,y),len(seq),list(seq)根据字符串创建列表,max( ...

  5. BZOJ 1251: 序列终结者 [splay]

    1251: 序列终结者 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3778  Solved: 1583[Submit][Status][Discu ...

  6. 最长不下降序列nlogn算法

    显然n方算法在比赛中是没有什么用的(不会这么容易就过的),所以nlogn的算法尤为重要. 分析: 开2个数组,一个a记原数,f[k]表示长度为f的不下降子序列末尾元素的最小值,tot表示当前已知的最长 ...

  7. [LeetCode] Sequence Reconstruction 序列重建

    Check whether the original sequence org can be uniquely reconstructed from the sequences in seqs. Th ...

  8. [LeetCode] Binary Tree Longest Consecutive Sequence 二叉树最长连续序列

    Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...

  9. [LeetCode] Repeated DNA Sequences 求重复的DNA序列

    All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...

随机推荐

  1. luoguP2398 GCD SUM [gcd]

    题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入格式: n 输出格式: sum ...

  2. LUOGU P4253 [SCOI2015]小凸玩密室(树形dp)

    传送门 解题思路 玄学树形\(dp\),题目描述极其混乱...看错了两次题,设首先根据每次必须点完子树里的灯才能点别的,那么点灯情况只有两种,第一种是点到某一个祖先,第二种是点到某一个祖先的兄弟.所以 ...

  3. python实现全局配置和用户配置文件

    一.文件目录格式 二.代码 1.conf.__init__.py import importlib import os from conf import gsettings class Setting ...

  4. EL fmt标签

    c:formate 表达式需要传入的对象为date

  5. codeforces 1100D-Dasha and Chess

    传送门:QAQQAQ 题意:This is an interactive task. 999*999国际象棋棋盘中有一个王和666个车,玩家走王,电脑走车,玩家先走,玩家的目的是让对方的车将到自己的王 ...

  6. Android按钮绑定四种方式

    public class MainActivity extends Activity implements OnClickListener{ @Override protected void onCr ...

  7. java模拟页面表单登录

    简单的通过表单的post请求提交到后台 package testpostlogin; import java.io.BufferedReader; import java.io.File; impor ...

  8. vue项目的实用配置

    文件压缩如何去掉console 在使用vue开发项目的过程中,免不了在调试的时候会写许多console,在控制台进行调试:在开发的时候这种输出是必须的,但是build后线上运行时这个东西是不能出现的: ...

  9. angular 级联选择

    HTML: <link rel="stylesheet" href="views/tree/checkbox.css"/> <div clas ...

  10. Qt分割线

    方法:使用QFrame QFrame * line = new QFrame(); line->setFrameShape(QFrame::HLine); line->setFrameSh ...