zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    mybatis数组和集合的长度判断及插入
    Getting Started with JavaFX
    抛出 NoClassDefFoundError: javax/validation/constraints/Size 问题的解决方法
    slf4japi整合maven 工程日志配置文件
    一场因OpenJDK引发的血案 之JavaFx
    Spring Boot logback springProperty 设置默认值
    java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive
    Linux curl命令使用代理、以及代理种类介绍
    Mybatis异常_03_Invalid bound statement (not found)
    Spring Boot 中文乱码问题解决方案汇总
  • 原文地址:https://www.cnblogs.com/lher/p/7637409.html
Copyright © 2011-2022 走看看