2017北京国庆刷题Day6 morning

期望得分:100+100+20=220

实际得分:100+100+20=220

 

模拟栈

#include<cstdio>
#include<cstring>
using namespace std;
#define N 10002
char s[N],st[N];
int top;
int main()
{
    freopen("kakutani.in","r",stdin);
    freopen("kakutani.out","w",stdout);
    int n,len,lt;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%s",s);
        len=strlen(s);
        top=0;
        for(int i=0;i<len;i++)
            if(s[i]=='4' || s[i]=='7') continue;
            else if(s[i]!='3') st[++top]=s[i];
            else 
            {
                if(st[top]=='1') top--; 
                else st[++top]='3';
            }
        if(top) for(int i=1;i<=top;i++) putchar(st[i]);
        else putchar('0');
        printf("\n");
    }
}
View Code

 

枚举i为间隔K个录像的左端点,那么间隔录像为[i,i+k-1]

设第一段为[Sa,Ta],第二段为[Sb,Tb],Ma为min[Sa,Ta],Mb为min[Sb,Tb]

随着Sa的左移,Ma单调不增

随着Tb的右移,Mb单调不增

如果枚举Sa,则有以下式子: Ta-Sa+1+Tb-Sb+1>=B

即Tb>=B+Sa+Sb-Ta-2

因为Tb右移,Mb单调不增,所以Tb取等号最优

所以二分Sa的位置,用st表查询Ma,Mb

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 1000001
using namespace std;
int st[N][21];
int p,n;
int logg2[N];
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
void stpre()
{
    p=log2(n);
    for(int j=1,k=2;j<=p;j++,k<<=1)
        for(int i=1;i+k-1<=n;i++)
            st[i][j]=min(st[i][j-1],st[i+(k>>1)][j-1]);
    for(int i=1;i<=n;i++) logg2[i]=log2(i);
}
int getmin(int s,int t)
{
    p=logg2[t-s+1];
    int len=1<<p;
    return min(st[s][p],st[t-len+1][p]);
}
int main()
{
    freopen("dota.in","r",stdin);
    freopen("dota.out","w",stdout); 
    int A,B,k;
    read(n); read(A); read(B); read(k);
    for(int i=1;i<=n;i++) read(st[i][0]);
    stpre();
    int Sa,Sb,Ta,Tb,Ma,Mb,Mi;
    int ans=0;
    int l,r,mid,tmp;
    for(int i=A+1;i<=n-A-k+1;i++)
    {
        Ta=i-1; Sb=i+k; 
        Tb=max(Sb+A-1,B+i-A+Sb-Ta-2);
        Ma=getmin(i-A,Ta); Mb=getmin(Sb,Tb); 
        l=1; r=i-A; tmp=min(Ma,Mb);
        while(l<=r)
        {
            mid=l+r>>1;
            Tb=max(Sb+A-1,B+mid+Sb-Ta-2);
            Ma=getmin(mid,Ta); Mb=getmin(Sb,Tb);
            tmp=max(tmp,min(Ma,Mb));
            if(Ma<Mb) l=mid+1;                
            else if(Ma==Mb) break;
            else r=mid-1;
        }
        ans=max(ans,tmp);
    }
    printf("%d",ans);
}
View Code

 

数位DP

dp[i][j][0/1] 前i位匹配到X的第j位,是否已经包含1个X的数的个数

二分,计算<=mid的数里的答案

其中的匹配用kmp

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
LL L,R,K;
LL dp[19][19][2];
int len,f[19];
char X[19];
int a[19],cnt;
void kmp()
{
    len=strlen(X);
    int j;
    for(int i=1;i<len;i++)
    {
        j=f[i];
        while(j && X[i]!=X[j]) j=f[j];
        f[i+1]=X[i]==X[j] ? j+1 : 0;
    }
}
LL dfs(int dep,int w,bool lim,bool get)
{
    if(!dep) return get;
    if(!lim && ~dp[dep][w][get]) return dp[dep][w][get];
    LL res=0;
    int k=lim ? a[dep] : 9;
    int j;
    for(int i=0;i<=k;i++)
    {
        j=w;
        while(j && X[j]-'0'!=i) j=f[j];
        if(X[j]-'0'==i) j++;
        res+=dfs(dep-1,j,lim&&(i==k),get||(j==len));
    }
    return lim ? res : dp[dep][w][get]=res;
}
LL query(LL lim)
{
    int cnt=0;
    while(lim)
    {
        a[++cnt]=lim%10;
        lim/=10;
    }
    memset(dp,-1,sizeof(dp));
    return dfs(cnt,0,true,false);
}
int main()
{
    freopen("spenum.in","r",stdin);
    freopen("spenum.out","w",stdout);
    scanf("%I64d%I64d%s%I64d",&L,&R,X,&K);
    kmp();
    LL tmp=query(L-1);
    if(query(R)<K) { puts("Hey,wake up!"); return 0; }
    LL l=L,r=R,ans,mid;
    while(l<=r)
    {
        mid=l+r>>1;
        if(query(mid)-tmp<K) l=mid+1;
        else ans=mid,r=mid-1;
    }
    printf("%I64d",ans);
}
View Code

 

posted @ 2017-10-06 19:08  TRTTG  阅读(300)  评论(0编辑  收藏  举报