20171005校内训练

给出一个美丽串,叫你找到下一个比它字典序大的回文串

我们考虑贪心的从后往前替换每一个字母。即对于最后一位(设字母为a),我们把它替换成从a到p的每个字母,如果都不满足美丽串的条件,那么把前一位字母从‘a'替换到p。

问题来了,判断回文串需要O(n)的时间。

分析条件:没有回文串其实就是每个字符不与前两个字符相同。

因为题目给出的是一个美丽串,所以对于当前字符,如果存在大于3长度的回文串,那么这个回文串的字串也一定回文,与题意说的美丽串不符

如图,若替换1号后会形成1234这个回文串,那么2号和3号一定相等,但是原串是个美丽串,即2,3号必不相等,矛盾

然后贪心找出了最高位的数字后,从后往前贪心构造每一位。

即从字典序从小到大选择每一位上填的数,如果可以,则继续下一位

#include<iostream>
#include<cstdio>
using namespace std;
int n,p;char c[100001];
bool check(int i)
{
    if(i==0)return 0;
    if(i==1)return c[i]==c[i-1];
    if(c[i]==c[i-1]||c[i]==c[i-2])return 1;
    return 0;
}
void up(int i)
{
    for(;i<n;i++)
    {
        for(int j=1;j<=p;j++)
        {
            c[i]='a'+j-1;
            if(!check(i))break;
        }
    }
}
int main()
{
    //freopen("string.in","r",stdin);freopen("string.out","w",stdout);
    scanf("%d%d%s",&n,&p,c);bool fir=0;
    int i;
    for(i=n-1;i>=0;i--)
    {
        while(fir==0||(c[i]<='a'+p-1&&check(i))){c[i]++;fir=1;}
        if(c[i]<='a'+p-1){up(i+1);break;}
        else fir=0;
    }
    if(i==-1)return 0*puts("NO");
    for(int i=0;i<n;i++)printf("%c",c[i]);
    return 0;
}
View Code

先说结论:答案为n-最长连续上升子序列

显而易见的,每个数最多只会被移动1次

序列中总是存在一些需要移动的和不需要移动的数(下图红色表示需要移动,绿色表示不需要移动)

移动完的序列肯定是长这样的

由于最终移动完的序列有序且连续,所以那些没被移动过的(绿色的)一定是上升且连续的。

所以最小的需要移动的数的个数(红色的)就等于n-最长连续上升子序列

怎么找最长连续上升子序列?

用一个数组wz[]记录每个数出现的位置

从1开始找,如果wz[i+1]>wz[i],那我们就i++,否则计算答案后i++

#include<cstdio>
#include<iostream>
using namespace std;
int wz[100001],a[100001];
int main()
{
    //freopen("sorting.in","r",stdin);freopen("sorting.out","w",stdout);
    int n;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);wz[a[i]]=i;}
    int now=1,ans=0;
    while(now<=n)
    {
        int p=now;
        while(wz[now+1]>wz[now])now++;
        ans=max(ans,now-p+1);now++;
    }
    printf("%d",n-ans);
}
View Code

 

从每个点开始进行一次bfs求出任意两个点间的最短路

对于一条路径a -> b -> c -> d,我们暴力枚举b,c,那么a是所有能到b的点中离b最远的一个点,同理,d是c出发所有能到的点的离c最远的一个点,这些我们都可以预处理出。

但是,这道题没那么简单。四个景点不能重复!

因为a最多只会和c,d重复,d最多只会和a,b重复,所以我们处理出从每个点开始到达的第一,第二,第三远的点以及到每个点的第一,第二,第三远的点,这样一定能包含互不重复的a,b,c,d四个点

时间复杂度O(9n^2)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int d[2001][2001],que[2101];bool used[2001];
int h[2010],to[10010],next[10010],k=0;
int _to[2001][4],from[2001][4],maxt[2001][4],maxf[2001][4];
void ins(int u,int v){next[++k]=h[u];h[u]=k;to[k]=v;}
void bfs(int S)
{
    memset(used,0,sizeof(used));
    int head=0,tail=0;
    que[tail++]=S;used[S]=1;d[S][S]=0;
    while(head<tail)
    {
        int u=que[head++];
        for(int i=h[u];i;i=next[i])
        {
            int v=to[i];if(!used[v]){used[v]=1;d[S][v]=d[S][u]+1;que[tail++]=v;}
        }
    }
}
int main()
{
//    freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);
    memset(d,127,sizeof(d));int inf=d[0][0],ans=0;
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);ins(u,v);}
    for(int i=1;i<=n;i++)bfs(i);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if(i==j||d[i][j]==inf)continue;
        if(d[i][j]>maxf[i][3])maxf[i][3]=d[i][j],from[i][3]=j;
        if(maxf[i][3]>maxf[i][2])swap(maxf[i][3],maxf[i][2]),swap(from[i][3],from[i][2]);
        if(maxf[i][2]>maxf[i][1])swap(maxf[i][2],maxf[i][1]),swap(from[i][2],from[i][1]);
        if(d[i][j]>maxt[j][3])maxt[j][3]=d[i][j],_to[j][3]=i;
        if(maxt[j][3]>maxt[j][2])swap(maxt[j][3],maxt[j][2]),swap(_to[j][3],_to[j][2]);
        if(maxt[j][2]>maxt[j][1])swap(maxt[j][2],maxt[j][1]),swap(_to[j][2],_to[j][1]);
    }
    int aa,bb,cc,dd;
    for(int j=1;j<=n;j++)
    for(int k=1;k<=n;k++)
    {
        if(j==k||d[j][k]==inf)continue;
        for(int i=1;i<=3;i++)
        {
            if(_to[j][i]==k||!_to[j][i])continue;
            for(int l=1;l<=3;l++)
            {
                if(from[k][l]==j||!from[k][l]||from[k][l]==_to[j][i])continue;
                if(d[_to[j][i]][j]+d[j][k]+d[k][from[k][l]]>ans)
                ans=d[_to[j][i]][j]+d[j][k]+d[k][from[k][l]],
                aa=_to[j][i],bb=j,cc=k,dd=from[k][l];
            }
        }
    }
    printf("%d %d %d %d",aa,bb,cc,dd);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lher/p/7637409.html