【简要题解】Hihocoder 重复旋律1-8简要题解

编号 名称标签 难度
1403 后缀数组一·重复旋律 Lv.4
1407 后缀数组二·重复旋律2 Lv.4
1415 后缀数组三·重复旋律3 Lv.4
1419 后缀数组四·重复旋律4 Lv.4
1445 后缀自动机二·重复旋律5 Lv.4
1449 后缀自动机三·重复旋律6 Lv.4
1457 后缀自动机四·重复旋律7 Lv.1
1465 后缀自动机五·重复旋律8 Lv.1
1466 后缀自动机六·重复旋律9 Lv.1

后缀数组

思路简单但是实现要想一想?之前我看的是什么lj教程,不如自己xjb强行写一下递归形式的然后改成循环就好了(我自己写的跑得贼慢,什么时候看看别人咋改进的)

关于height数组,它的性质是显然的就不讲了,不过height数组给人的启示是,带有前缀交性质的查询可以将元素按照字典序排序,这样连续一段的前缀交=\((l,R]\)的相邻前缀交了。同时也有\(h[i]\ge h[i-1]-1\)这个结论。

重复旋律1

题目大意是问你满足这个条件的子串的最长长度

条件:在母串出现次数至少为k次(可以重叠出现)

子串=后缀的前缀,现在只要定位height数组任意一个长度为k-1的子段,查询一下其中的最小值,我们是要求这些最小值的最大值。线段树就行了

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
#define DEBUG(s,a) cerr<<#s" = "<<(s)<<" \n"[(a)==1] using namespace std; typedef long long ll; char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e5+5;
char c[maxn];
int sa[maxn],h[maxn],rk[maxn],seg[maxn<<2],n; void sufsort(char*c,int*sa,int*rk,int*h,int n){
static int temp[maxn<<1],b[maxn];
c[0]='!';
for(int k=0,m=128;(1<<k>>1)<=n;++k){
if(!k) for(int t=1;t<=n;++t) temp[t]=t,rk[t]=c[t],temp[t+n]=0;
int l=1<<k>>1,p=0,q=l;
for(int t=1;t<=n;++t){
if(sa[t]>=n-l+1) temp[++p]=sa[t];
if(sa[t]>l) temp[++q]=sa[t]-l;
}
for(int t=1;t<=n;++t) ++b[rk[t]];
for(int t=1;t<=m;++t) b[t]+=b[t-1];
for(int t=n;t;--t) sa[b[rk[temp[t]]]--]=temp[t];
memset(b,0,(m+1)<<2); memcpy(temp+1,rk+1,n<<2); rk[sa[1]]=1;
for(int t=2;t<=n;++t)
rk[sa[t]]=temp[sa[t]]==temp[sa[t-1]]&&temp[sa[t]+l]==temp[sa[t-1]+l]?rk[sa[t-1]]:rk[sa[t-1]]+1;
m=rk[sa[n]];
}
for(int t=1,l=0;t<=n;++t){
if(l) --l;
if(rk[t]>1) while(c[t+l]==c[sa[rk[t]-1]+l]) ++l;
else l=0;
h[rk[t]]=l;
}
} void build(int l,int r,int pos){
if(l==r) return seg[pos]=h[l],void();
build(lef); build(rgt);
seg[pos]=min(seg[pos<<1],seg[pos<<1|1]);
} int que(int L,int R,int l,int r,int pos){
if(L>r||R<l) return 1e9;
if(L<=l&&r<=R) return seg[pos];
return min(que(L,R,lef),que(L,R,rgt));
} int que(int l,int r){
if(rk[l]>rk[r]) swap(l,r);
return que(rk[l]+1,rk[r],1,n,1);
} int main(){
scanf("%s",c+1); n=strlen(c+1);
sufsort(c,sa,rk,h,n);
build(1,n,1);
int ans=0;
for(int t=1;t<=n;++t)
for(int i=1;i<=n-t;i+=t){
int k=que(i,i+t);
ans=max(ans,k/t+1);
if(i>=t-k%t) ans=max(que(i-t+k%t,i+k%t)/t+1,ans);
}
printf("%d\n",ans);
return 0;
}

重复旋律2

题目大意是问你满足这个条件的子串的最长长度

条件:在母串出现次数至少为k次(不可以重叠出现)

现在问题其实就变成了:

\[\max l \text{ 使得}
\\
\exist i,j \text{ 满足 } i<j-l \and \text{lcp}(i,j)\ge l
\]

显然满足二分性,二分就行。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define DEBUG(s,a) cerr<<#s" = "<<(s)<<" \n"[(a)==1]
#define mid ((l+r)>>1) using namespace std; typedef long long ll;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e5+5;
int rk[maxn],sa[maxn],c[maxn],height[maxn],n; inline void sufsort(int*str,int*sa,int*rk,int*height,int n){
static int temp[maxn<<1],buk[maxn];
str[0]=-1;
for(int k=0,m=1000;(1<<k>>1)<=n;++k){
if(!k) for(int t=1;t<=n;++t) temp[t]=t,temp[t+n]=0,rk[t]=str[t];
int l=1<<k>>1,p=0,q=l;
for(int t=1;t<=n;++t){
if(sa[t]>=n-l+1) temp[++p]=sa[t];
if(sa[t]>l) temp[++q]=sa[t]-l;
}
for(int t=1;t<=n;++t) ++buk[rk[t]];
for(int t=1;t<=m;++t) buk[t]+=buk[t-1];
for(int t=n;t;--t) sa[buk[rk[temp[t]]]--]=temp[t];
memset(buk,0,(m+1)<<2); memcpy(temp+1,rk+1,n<<2); rk[sa[1]]=1;
for(int t=1;t<=n;++t)
rk[sa[t]]=temp[sa[t]]==temp[sa[t-1]]&&temp[sa[t]+l]==temp[sa[t-1]+l]?rk[sa[t-1]]:rk[sa[t-1]]+1;
m=rk[sa[n]];
}
for(int t=1,l=0;t<=n;++t){
if(l) --l;
if(rk[t]>1) while(str[t+l]==str[sa[rk[t]-1]+l]) ++l;
else l=0;
height[rk[t]]=l;
}
} bool chek(int k){
for(int l=1,r=1;r<=n;l=++r){
if(height[l]<k) continue;
int Min=sa[l],Max=sa[l];
if(l>1) Min=min(sa[l-1],Min),Max=max(Max,sa[l-1]);
while(r<n&&height[r+1]>=k) ++r,Min=min(Min,sa[r]),Max=max(Max,sa[r]);
if(Max-Min+1>k) return 1;
}
return 0;
} int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
n=qr();
for(int t=1;t<=n;++t) c[t]=qr();
sufsort(c,sa,rk,height,n);
int l=0,r=n;
do
if(chek(mid)) l=mid+1;
else r=mid-1;
while(l<=r);
printf("%d\n",r);
return 0;
}

重复旋律3

问两个串的最长公共子串。

按道理应该可以AC自动机做,但是我没想出来

把两个串顺序连接在一起,中间设放一个分隔符位置设为k,问题就变成了

\[\max l \text{ 使得}
\\
\exist i,j \text{ 满足 } i<k\and j>k \and \text{lcp}(i,j)\ge l
\]

显然满足二分性,直接二分就行

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
#define DEBUG(s,a) cerr<<#s" = "<<(s)<<" \n"[(a)==1] using namespace std; typedef long long ll; char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=2e5+5;
int sa[maxn],rk[maxn],height[maxn],n,k;
char c[maxn]; void sufsort(char*str,int*sa,int*rk,int*height,int n){
static int temp[maxn<<1],buk[maxn];
str[0]='~';
for(int k=0,m=1000;(1<<k>>1)<=n;++k){
if(!k) for(int t=1;t<=n;++t) temp[t]=t,temp[t+n]=0,rk[t]=str[t];
int l=1<<k>>1,p=0,q=l;
for(int t=1;t<=n;++t){
if(sa[t]>=n-l+1) temp[++p]=sa[t];
if(sa[t]>l) temp[++q]=sa[t]-l;
}
for(int t=1;t<=n;++t) ++buk[rk[t]];
for(int t=1;t<=m;++t) buk[t]+=buk[t-1];
for(int t=n;t;--t) sa[buk[rk[temp[t]]]--]=temp[t];
memset(buk,0,(m+1)<<2); memcpy(temp+1,rk+1,n<<2); rk[sa[1]]=1;
for(int t=2;t<=n;++t)
rk[sa[t]]=temp[sa[t]]==temp[sa[t-1]]&&temp[sa[t]+l]==temp[sa[t-1]+l]?rk[sa[t-1]]:rk[sa[t-1]]+1;
m=rk[sa[n]];
}
for(int t=1,l=0;t<=n;++t){
if(l) --l;
if(rk[t]>1) while(str[t+l]==str[sa[rk[t]-1]+l]) ++l;
else l=0;
height[rk[t]]=l;
}
} bool chek(int L){
for(int l=1,r=1;r<=n;l=++r){
if(height[l]<L) continue;
int Min=sa[l],Max=sa[l];
if(l>1) Min=min(sa[l-1],Min),Max=max(Max,sa[l-1]);
while(r<n&&height[r+1]>=L) ++r,Min=min(Min,sa[r]),Max=max(Max,sa[r]);
if(Min<k&&Max>k) return 1;
}
return 0;
} int main(){
scanf("%s",c+1);
n=strlen(c+1); c[k=++n]='_';
scanf("%s",c+n);
n=strlen(c+1);
sufsort(c,sa,rk,height,n);
int l=0,r=n;
do
if(chek(mid)) l=mid+1;
else r=mid-1;
while(l<=r);
printf("%d\n",r);
return 0;
}

重复旋律4

题意是问你,母串的某个子段可以被表示成k个相同的串重复k次,给你母串问你最大可能的k

用别的方法描述一下这个问题,就变成了要你在母串中找到一个位置的数列\(P=\{p_i\}\)满足\(P\)是一个等差数列且要求任意两个\(p\)的\(\text{lcp} \ge d\) ,答案是最大的\(|P|\)。

检查一个串是否是由某个串重复很多次得到,只要需要枚举长度i然后比对原串和suf[i]是否相同即可。匹配出来得到的长度\(l\)显然是小于重复长度+i的。这是因为将串平移后和自己匹配的诸多性质。

但是现在还需要枚举一个偏移量,实际上我们不需要枚举这个偏移量,直接枚举每个长度然后枚举这个长度的倍数。我们可以发现,假设最优答案的起始位置的偏移=k,那么我们一定在某次查询时,少算了一个循环。此时可以发现,少算的那个被我们枚举的分界点分开了,具体分界点在哪里,假设查询出来长度为j,分界点就在负偏移j%i处。每次算一下就行,这样就一定会统计到最优答案。

因为每次统计答案的时候,统计出来的值都是真的(就是合法的,不会比答案大),所以每次弄就行。

序列上的等差子序列问题一般和一个复杂度是调和级数\((O(1))\)的经典做法有关...

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
#define DEBUG(s,a) cerr<<#s" = "<<(s)<<" \n"[(a)==1] using namespace std; typedef long long ll; char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e5+5;
char c[maxn];
int sa[maxn],h[maxn],rk[maxn],seg[maxn<<2],n; void sufsort(char*c,int*sa,int*rk,int*h,int n){
static int temp[maxn<<1],b[maxn];
c[0]='!';
for(int k=0,m=128;(1<<k>>1)<=n;++k){
if(!k) for(int t=1;t<=n;++t) temp[t]=t,rk[t]=c[t],temp[t+n]=0;
int l=1<<k>>1,p=0,q=l;
for(int t=1;t<=n;++t){
if(sa[t]>=n-l+1) temp[++p]=sa[t];
if(sa[t]>l) temp[++q]=sa[t]-l;
}
for(int t=1;t<=n;++t) ++b[rk[t]];
for(int t=1;t<=m;++t) b[t]+=b[t-1];
for(int t=n;t;--t) sa[b[rk[temp[t]]]--]=temp[t];
memset(b,0,(m+1)<<2); memcpy(temp+1,rk+1,n<<2); rk[sa[1]]=1;
for(int t=2;t<=n;++t)
rk[sa[t]]=temp[sa[t]]==temp[sa[t-1]]&&temp[sa[t]+l]==temp[sa[t-1]+l]?rk[sa[t-1]]:rk[sa[t-1]]+1;
m=rk[sa[n]];
}
for(int t=1,l=0;t<=n;++t){
if(l) --l;
if(rk[t]>1) while(c[t+l]==c[sa[rk[t]-1]+l]) ++l;
else l=0;
h[rk[t]]=l;
}
} void build(int l,int r,int pos){
if(l==r) return seg[pos]=h[l],void();
build(lef); build(rgt);
seg[pos]=min(seg[pos<<1],seg[pos<<1|1]);
} int que(int L,int R,int l,int r,int pos){
if(L>r||R<l) return 1e9;
if(L<=l&&r<=R) return seg[pos];
return min(que(L,R,lef),que(L,R,rgt));
} int que(int l,int r){
if(rk[l]>rk[r]) swap(l,r);
return que(rk[l]+1,rk[r],1,n,1);
} int main(){
scanf("%s",c+1); n=strlen(c+1);
sufsort(c,sa,rk,h,n);
build(1,n,1);
int ans=0;
for(int t=1;t<=n;++t)
for(int i=1;i<=n-t;i+=t){
int k=que(i,i+t);
ans=max(ans,k/t+1);
if(i>=t-k%t) ans=max(que(i-t+k%t,i+k%t)/t+1,ans);
}
printf("%d\n",ans);
return 0;
}

重复旋律5

答案=\(\sum len-len[fa]\)

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector> using namespace std; typedef long long ll;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1000000+5;
int fa[maxn<<1],len[maxn<<1],trans[maxn<<1][26],siz[maxn<<1],last=1,cnt=1;
vector<int> e[maxn<<1];
char buf[maxn]; void insert(int c){
int u=++cnt,v=last;
len[u]=len[v]+1;
while(v&&!trans[v][c]) trans[v][c]=u,v=fa[v];
if(!v) fa[u]=1;
else {
int x=trans[v][c];
if(len[x]==len[v]+1) fa[u]=x;
else {
int y=++cnt;
for(int t=0;t<26;++t) trans[y][t]=trans[x][t];
fa[y]=fa[x]; fa[x]=fa[u]=y; len[y]=len[v]+1;
while(v&&trans[v][c]==x) trans[v][c]=y,v=fa[v];
}
}
siz[u]=1; last=u;
} ll ans;
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
#endif
scanf("%s",buf);
for(int t=0,ed=strlen(buf);t<ed;++t) insert(buf[t]-'a');
for(int t=1;t<=cnt;++t) ans+=len[t]-len[fa[t]];
printf("%lld\n",ans);
return 0;
}

重复旋律6

每个状态对于\([len[fa]+1,len[i]]\)都有\(|endpos|\)的贡献(取max),弄个线段树就行了

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> #define mid ((l+r)>>1)
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
#define getchar() (__c==__ed?(__ed=__buf+fread(__c=__buf,1,1<<19,stdin),*__c++):*__c++)
using namespace std; typedef long long ll; char __buf[1<<19],*__c=__buf,*__ed=__buf; const int maxn=2e6+6;
int fa[maxn],len[maxn],siz[maxn],trans[maxn][26],cnt=1,last=1;
int head[maxn],seg[maxn<<1],tag[maxn<<1],n;
struct E{int to,nx;}e[maxn<<1]; void add(int fr,int to){
static int cnt=0;
e[++cnt]={to,head[fr]}; head[fr]=cnt;
e[++cnt]={fr,head[to]}; head[to]=cnt;
} void insert(int c){
int u=++cnt,v=last;
len[u]=len[v]+1;
while(v&&!trans[v][c]) trans[v][c]=u,v=fa[v];
if(!v) fa[u]=1;
else {
int x=trans[v][c];
if(len[x]==len[v]+1) fa[u]=x;
else {
int y=++cnt;
for(int t=0;t<26;++t) trans[y][t]=trans[x][t];
fa[y]=fa[x]; fa[x]=fa[u]=y; len[y]=len[v]+1;
while(v&&trans[v][c]==x) trans[v][c]=y,v=fa[v];
}
}
siz[u]=1; last=u;
} void pd(int pos){
if(tag[pos]){
seg[pos<<1]=max(seg[pos<<1],tag[pos]);
seg[pos<<1|1]=max(seg[pos<<1|1],tag[pos]);
tag[pos<<1]=max(tag[pos<<1],tag[pos]);
tag[pos<<1|1]=max(tag[pos<<1|1],tag[pos]);
tag[pos]=0;
}
} void pp(int pos){seg[pos]=max(seg[pos<<1],seg[pos<<1|1]);} void ans(int l,int r,int pos){
if(l==r) return printf("%d\n",seg[pos]),void();
pd(pos); ans(lef); ans(rgt);
} void upd(int v,int L,int R,int l,int r,int pos){
if(L>r||R<l) return;
if(L<=l&&r<=R) return seg[pos]=max(seg[pos],v),tag[pos]=max(tag[pos],v),void();
pd(pos); upd(v,L,R,lef); upd(v,L,R,rgt);
} void dfs(int now,int last){
for(int t=head[now];t;t=e[t].nx)
if(e[t].to!=last)
dfs(e[t].to,now),siz[now]+=siz[e[t].to];
upd(siz[now],len[last]+1,len[now],1,n,1);
} int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
for(char c=getchar();isalpha(c);c=getchar()) ++n,insert(c-'a');
for(int t=1;t<=cnt;++t) add(t,fa[t]);
dfs(1,0); ans(1,n,1);
return 0;
}

重复旋律7

考虑串之间插入分隔符,随后将分隔符对于的辅助点直接从DAG上删掉,然后把从1不可达的点删掉,在这个图上跑一个DP即可。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<assert.h>
#include<algorithm>
#include<vector>
#include<queue> using namespace std; typedef long long ll;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1.5e6+5;//shall be 4e6 ?
const int mod=1e9+7;
int fa[maxn],trans[11][maxn],len[maxn],n,cnt=1,last=1,head[maxn],dr[maxn];
int dp[maxn],f[maxn];
bool is[maxn]; inline int MOD(const int&x){return x>=mod?x-mod:x;}
inline int MOD(const int&x,const int&y){return 1ll*x*y%mod;} struct E{int to,nx,w;}e[maxn*11];
void add(int fr,int to,int w){static int cnt=0;e[++cnt]={to,head[fr],w};head[fr]=cnt;++dr[to];
//cerr<<fr<<' '<<to<<' '<<w<<endl;
} void insert(int c){
int u=++cnt,v=last;
len[u]=len[v]+1;
while(v&&!trans[c][v]) trans[c][v]=u,v=fa[v];
if(!v) fa[u]=1;
else {
int x=trans[c][v];
if(len[x]==len[v]+1) fa[u]=x;
else {
int y=++cnt;
for(int t=0;t<=10;++t) trans[t][y]=trans[t][x];
fa[y]=fa[x]; fa[x]=fa[u]=y; len[y]=len[v]+1;
while(v&&trans[c][v]==x) trans[c][v]=y,v=fa[v];
}
}
last=u;
} queue<int> q;
void topo(){
q.push(1);
f[1]=1;
while(q.size()){
int now=q.front();
q.pop();
for(int t=head[now];t;t=e[t].nx){
if(e[t].w<10) f[e[t].to]=MOD(f[e[t].to]+f[now]),dp[e[t].to]=MOD(MOD(MOD(dp[now],10)+MOD(e[t].w,f[now]))+dp[e[t].to]);
if(--dr[e[t].to]==0) q.push(e[t].to);
}
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
#endif
n=qr();
for(int t=1,c;t<=n;++t){
c=getchar();
while(!isdigit(c)) c=getchar();
while( isdigit(c)) insert(c-48),c=getchar();
insert(10);
}
for(int i=0;i<=10;++i)
for(int t=1;t<=cnt;++t)
if(trans[i][t]) add(t,trans[i][t],i);
topo();
int ans=0;
for(int t=1;t<=cnt;++t) ans=MOD(ans+dp[t]);
printf("%d\n",ans);
return 0;
}

重复旋律8,9

懒得更了...

【简要题解】Hihocoder 重复旋律1-9简要题解的更多相关文章

  1. HihoCoder 重复旋律

    あの旋律を何度も繰り返しでも.あの日見た光景を再現できない 无论将那段旋律重复多少次,也无法重现那一日我们看到的景象 もし切ないならば.時をまきもどしてみるかい? 若是感到惆怅的话,要试着让时光倒流吗 ...

  2. 后缀数组之hihocoder 重复旋律1-4

    蒟蒻知道今天才会打后缀数组,而且还是nlogn^2的...但基本上还是跑得过的: 重复旋律1: 二分答案,把height划分集合,height<mid就重新划分,这样保证了每个集合中的LCP&g ...

  3. hihocoder #1419 : 后缀数组四·重复旋律4

    #1419 : 后缀数组四·重复旋律4 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构 ...

  4. 【hihoCoder 1419】重复旋律4

    Description 小 Hi 平时的一大兴趣爱好就是演奏钢琴. 我们知道一个音乐旋律被表示为长度为 N的数构成的数列. 小 Hi 在练习过很多曲子以后发现很多作品中的旋律有重复的部分. 我们把一段 ...

  5. hihoCoder 1403 后缀数组一·重复旋律(后缀数组+单调队列)

    #1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...

  6. 【题解】Comet OJ Round 70 简要题解

    [题解]Comet OJ Round 70 简要题解 A 将放在地上的书按照从小到大排序后,问题的本质就变成了合并两个序列使得字典序最小.可以直接模拟归并排序.直接用循环和std::merge实现这个 ...

  7. hihoCoder 后缀自动机三·重复旋律6

    后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...

  8. hihoCoder #1445 : 后缀自动机二·重复旋律5

    #1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...

  9. hihoCoder 后缀数组 重复旋律

    #1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...

随机推荐

  1. Python中json和eval的区别

    >>> import json >>> s = '{"one":1,"two":2}' >>> json. ...

  2. QQ 聊天机器人API

    QQ机器人是腾讯陆续推出的的人工智能聊天机器人的总称. 都说小Q妹妹聪明好学,我们能够教她说话.也能够请他帮忙查询邮编.手机号,或者解释成语.翻译成语,据说她还会查询手机号码归属地.应用科学计算器. ...

  3. 阿里云POLARDB荣膺2019中国数据库年度最佳创新产品

    在日前的DTCC 2019(第十届中国数据库技术大会)上,阿里云自研云原生数据库POLARDB获选2019中国数据库——“年度最佳创新产品”. POLARDB是阿里云在2018年正式商业化的云原生数据 ...

  4. 给博客添加rss订阅

    如果是自己搭建博客,有一个问题是如何写一篇新的文章就可以告诉读者,你写了一篇新的?一个简单方法是使用 rss ,RSS订阅是站点用来和其他站点之间共享内容的一种简易方式,即Really Simple ...

  5. 怎样打开.jar格式文件,怎样运行.jar格式文件

    当时第一次看到.jar文件不知道是什么鬼,以为是压缩包,直接就解压了,但是并没有什么用.所以在下为大家详细介绍如何打开.jar文件以及如何运行.jar文件.什么是.jar文件,简单的说就是java压缩 ...

  6. UVa11400 - Lighting System Design——[动态规划]

    题干略. 题意分析: 很容易理解一类灯泡要么全部换要么全不换,其实费用节省的主要原因是由于替换灯泡类型而排除了低压电压源,于是我们就可以推断出灯泡类型替换的原则: 对于两类灯泡a1和a2,a1可以被a ...

  7. Python--day47--mysql执行计划

    1,什么是mysql执行计划? 让mysql预估执行操作:在要执行的语句前面加explain,就不会真的执行sql语句,只是给出了要执行的数据的情况,如大约有多少条,查询类型.

  8. HDU 5971"Wrestling Match"(二分图染色)

    传送门 •题意 给出 n 个人,m 场比赛: 这 m 场比赛,每一场比赛中的对决的两人,一个属于 "good player" 另一个属于 "bad player" ...

  9. @JsonIgnore @JsonIdentityInfo 处理Hibernate 循环引用的问题

    enterprise和user一对一的关系: @Entity @Table(name = "enterprise") public class Enterprise extends ...

  10. Gora是一个类似Hibernate的ORM框架

    Gora是一个类似Hibernate的ORM框架,但是不只是支持关系数据库,更重要支持NoSQL之类大数据的存储. 支持NoSQL之类大数据的存储 Apache Gora是一个开源的ORM(Objec ...