zoukankan      html  css  js  c++  java
  • UVALive-3716 DNA Regions

    题目大意:

    有两个字符串, 现在要你选择一个区间[ l , r ], 要求这个区间内部两个串不相同的位置小于等于p%, 求这个区间最长是多长.

    设dp[ i ]表示以i为结尾的满足条件的最长串长度是多少.

    然后我们观察一下转移条件, 我们可以发现, 需要满足的条件是(sum[ i ]-sum[ j ])/( i-j )<=p/100, 其中sum表示不相同的位置的前缀和.

    日常化式子就可以得到sum[ i ]*100-p*i<=sum[ j ]*100-p*j, 所以我们需要的就是满足条件的最小的j.

    那么我们把这个值记为f, 丢到一个数组( 其实这个数组就像是一个单调栈, 但是单调性维护不一样 )里面.

    如果当前i的f[ i ]大于数组最后一个( 可以理解为栈顶 ), 就直接把j压进去, 因为不存在f[ j ]比f[ i ]大了,这样就保证了这个数组( 单调栈 )是按f递增的;

    如果小于最后一个, 就在存的这个数组中二分查找大于f[ i ]的最小的f[ j ].

    由于我们放进去是从前往后放的, 所以数组中的f[ j ]对应的j也是递增的, 选择最小的f[ j ]就是最小的j, 此时长度也是最长的, 然后dp[ i ]=i-j.

    查找了就不用再压到数组里面去了.

    因为后面的是查找最小的j满足f[ i ]<=f[ j ], 而当前i进行二分查找就说明数组中存了比当前f[ i ]大的f[ j ], 且这个j在当前i前面, 如果后面有一个i'满足f[ i' ]<=f[ i ], 那么也满足f[ i' ]<=f[ j ], 且i和i'的距离要比j和i'的距离远, 所以直接弃掉当前的f[ i ]没问题.

    其实有许多东西都是可以不用开的, 比方说sum[ i ]和dp[ i ], 直接用变量记下来就可以了.

    实时对ans取min.

    代码如下:

    //made by Crazy01
    #include<bits/stdc++.h>
    #define inf 1<<30
    #define ll long long
    #define db double
    #define c233 cout<<"233"<<endl
    #define mem(s) memset(s,0,sizeof(s))
    const int N=150050;
    using namespace std;
    
    char a[N],b[N];
    int f[N];
    int n,p,ans,sum;
    struct lll{
      int q[N];
      int tp;
      void clear(){q[0]=0; tp=0;}
      bool empty(){return tp==0;}
      void push(int x){q[++tp]=x;}
      bool ck(int x){return f[q[tp]]<f[x];}
      int lyb(int x){
        int l=0,r=tp;
        while(l<=r){
          int mid=(l+r)>>1;
          if(f[q[mid]]<f[x])l=mid+1;
          else r=mid-1;
        }
        return q[l];
      }
    }q;
    
    inline int gi(){
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+ch-48,ch=getchar();
      return x*res;
    }
    
    void init(){
      p=gi();
      scanf("%s",a+1);
      scanf("%s",b+1);
    }
    
    void work(){
      ans=sum=0;
      for(int i=1;i<=n;i++){
        sum+=(a[i]!=b[i]);
        f[i]=100*sum-p*i;
        if(q.ck(i)){q.push(i);continue;}
        ans=max(ans,i-q.lyb(i));
      }
      if(ans)printf("%d
    ",ans);
      else printf("No solution.
    ");
    }
    
    int main(){
      n=gi();
      while(n){
        q.clear();
        init();
        work();
        n=gi();
      }
      return 0;
    }
  • 相关阅读:
    67家基金子公司背景脉络梳理
    港股奇葩术语知多少
    68家信托公司7大派系股东分食图谱
    港股术语
    流动性陷阱
    ORACLE归档模式和非归档模式的利与弊
    肥尾效应
    DVP
    金融衍生品如何定价
    绿鞋机制
  • 原文地址:https://www.cnblogs.com/Crazy01/p/7700079.html
Copyright © 2011-2022 走看看