HZOI2019序列
题目链接: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序列的更多相关文章
- 【夯实PHP基础】UML序列图总结
原文地址 序列图主要用于展示对象之间交互的顺序. 序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸.横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色 ...
- Windows10-UWP中设备序列显示不同XAML的三种方式[3]
阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universa ...
- 软件工程里的UML序列图的概念和总结
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 软件工程的一般开发过程:愿景分析.业务建模,需求分析,健壮性设计,关键设计,最终设计,实现…… 时序图也叫序列图(交互图),属于软件 ...
- python序列,字典备忘
初识python备忘: 序列:列表,字符串,元组len(d),d[id],del d[id],data in d函数:cmp(x,y),len(seq),list(seq)根据字符串创建列表,max( ...
- BZOJ 1251: 序列终结者 [splay]
1251: 序列终结者 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3778 Solved: 1583[Submit][Status][Discu ...
- 最长不下降序列nlogn算法
显然n方算法在比赛中是没有什么用的(不会这么容易就过的),所以nlogn的算法尤为重要. 分析: 开2个数组,一个a记原数,f[k]表示长度为f的不下降子序列末尾元素的最小值,tot表示当前已知的最长 ...
- [LeetCode] Sequence Reconstruction 序列重建
Check whether the original sequence org can be uniquely reconstructed from the sequences in seqs. Th ...
- [LeetCode] Binary Tree Longest Consecutive Sequence 二叉树最长连续序列
Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...
- [LeetCode] Repeated DNA Sequences 求重复的DNA序列
All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...
随机推荐
- hdu多校第四场 1007 (hdu6620) Just an Old Puzzle 逆序对
题意: 给你一个数字拼图,问你数字拼图能否能复原成原来的样子. 题解: 数字拼图的性质是,逆序数奇偶相同时,可以互相转化,逆序数奇偶不同,不能互相转化. 因此统计逆序对即可. #include< ...
- Mac+VS Code+Git+Github
https://blog.csdn.net/qq_37747262/article/details/81750417
- 在ubuntu下编写python
一般情况下,ubuntu已经安装了python,打开终端,直接输入python,即可进行python编写. 默认为python2 如果想写python3,在终端输入python3即可. 如果需要执行大 ...
- IO初步,字节输入流和字节输出流
字节输出流 OutputStream(基类,抽象) 特点:写任意的文件 方法:写出数据的方法:write write(int b) 写出1个字节 -128~127之间,写的是一个ASCLL码的值 wr ...
- POJ 3449 /// 判断线段相交
题目大意: 给出多个多边形及其编号 按编号顺序输出每个多边形与其相交的其他多边形编号 注意一个两个多个的不同输出 将每个多边形处理成多条边 然后去判断与其他多边形的边是否相交 计算正方形另外两点的方法 ...
- python语句结构(控制语句与pass语句)
python语句结构(控制语句和pass语句) break-跳出循环:语句可以跳出for和while语句的循环体.如果你从for和while循环中终止,任何对应循环的else语块均终止 continu ...
- Visual Studio 代码管理器svn插件下载
环境:Visual Studio 2010 Visual Studio的svn插件叫做VisualSVN,可自行到VisualSVN官网上下载相应版本,也可以通过vs中找到相关插件. ps:vs其他的 ...
- Leetcode931. Minimum Falling Path Sum下降路径最小和
给定一个方形整数数组 A,我们想要得到通过 A 的下降路径的最小和. 下降路径可以从第一行中的任何元素开始,并从每一行中选择一个元素.在下一行选择的元素和当前行所选元素最多相隔一列. 示例: 输入:[ ...
- Android开发 TextView的开发记录
前言 此篇博客是记录一些TextView开发上一些少用的开发功能项.目前开发记录如下: 添加图片 文字滚动 添加省略号 实现长文的收起和展开功能 改变一个字符串里自定字符的颜色或者大小 效果字体(粗体 ...
- 进程互斥软件实现之Lamport面包店算法
一. 进程互斥的实现方式 1. 软件方式: 保护临界区, 自己编写代码来实现对进程的控制. Dekker算法Peterson算法Lamport算法等 2. 硬件方式: 使用特殊指令保护临界区. 开关中 ...