【SMOJ】2017.10.18模拟赛27

关于SMOJ校内模拟赛,表示本蒟蒻一篇博文都没写过(除了上次dp专题)。
今天做的题目一下子难度就upup,感觉整个人都是炸裂的。暴打选题人

那么接下来让我们看一看这些dalao眼中的水题。

回文数

【SMOJ】2017.10.18模拟赛27_第1张图片
【SMOJ】2017.10.18模拟赛27_第2张图片
【分析】
一看数据范围,显然是一道数学题。既然是数学题,那我们还是赶紧秒了吧。
首先很明显,我们可以看到,当i%2==0,并没有什么卵用,因为布尔表达式的值为0,也就是说,我们要求的回文串全都是长度为奇数的。这样一来,这个回文串就可以表示为ABA的形式。不难发现,我们令A为任意一个数字,B可以取0~9任意一个数字。有什么用呢?
例如我们取A的长度为3,那么长度为3的数字有多少个?答案是999-99=900个。那么很显然,我们长度为7的回文串个数(即ABA形式),一共有900*10=9000个,其中10代表B可以为0~9。
这样一来,当加上权值,我们可以得到这样一个东西:
令k=(n+1)/2;
S[i]=n*10^k-222…(k个2)+1

然后我们发现前面的
n*10^k
是一个快速幂

后面的
222…(k个2)
就是
111…(k个1)*2
这个是可以用一个等比数列弄出来的…

然后就可以做了。
(考试的时候用了矩阵乘法来做这个k个2…常数8,然而T了,优化失败又不想改lg,放弃)

#include
#include
#include
#include
using namespace std;

typedef long long LL;
const LL MAXN=4;
const LL mod=233333;
LL n,k,ans;

inline LL readin()
{
    char ch=getchar();
    LL u=0;
    while(ch<'0' || ch>'9')
        ch=getchar();
    while(ch>='0' && ch<='9')
    {
        u=u*10+(ch-'0');
        ch=getchar();
    }
    return u;
}

inline void init()
{
    k=readin();
    if(k%2==0)
        --k;    
    n=k;
    k=(k+1)/2;
}

inline LL mi(LL tp,LL tk)
{
    --tk;
    LL ret=tp;
    for(;tk;tk>>=1,tp=(tp*tp)%mod)
    {
        if(tk&1)
            ret=(ret*tp)%mod;
    }
    return ret%mod;
}

inline void solve()
{
//  printf("%I64d\n",mi(10,k));
    LL tmpmi=((mi(10,k)-1)%mod);
//  printf("%I64d\n",tmpmi);
    ans=(tmpmi*25926)%mod;

    LL tenmi=mi(10,(n+1)>>1)%mod;
    LL tfir=((1ll*n%mod)*tenmi)%mod;

    ans=(ans*2)%mod;
    LL las=(tfir-ans+1+mod)%mod;
    printf("%lld\n",las);
}

int main()
{
    freopen("2255.in","r",stdin);
    freopen("2255.out","w",stdout);

    int T=readin();
    while(T--)
    {
        init();
        solve();
    }
    return 0;
}

购物

【SMOJ】2017.10.18模拟赛27_第3张图片

【分析】
这题在考试的时候想着用线段树各种维护,然后果断炸了啊。
机房的scx在赛后5min码出了正解

其实这是一道比较水的dp (题面加难度系列) 设f[i]表示取到点i(商店i),的最大ans。

然后实际上,我们考虑每一个点,要取这个点,当且仅当有区间是可以覆盖到这个点的。那么我们就可以考虑,对于所有包含这个点的区间,我们取一个距离这个点最远的l(用lef[i]来记录),那么lef[i]到i这中间的所有点(用j来枚举)我们可以假设作为分割点,这样并不会影响到最后答案。

于是我们有:

f[i]=max(f[i],f[j-1]+sqr(sum[i]-sum[j-1]))。

其中sum表示到1~i商店的价值和。

注意有的点是不能被覆盖到的,这样f[i]为0,我们需要用一个ans来把前后的都加上。(详见代码)

#include
#include
#include
#include
using namespace std;

typedef long long LL;
const int MAXN=5005;
int n,m;
int w[MAXN],lef[MAXN],sum[MAXN];
int ans,f[MAXN];

struct Tshop
{
    int l,r;
};
Tshop a[MAXN*200];

inline int cmp(Tshop A,Tshop B)
{
    if(A.l==B.l)
        return A.rreturn A.lint sq(int x)
{
    return x*x;
}

int main()
{
    freopen("2256.in","r",stdin);
    freopen("2256.out","w",stdout);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&w[i]);
        sum[i]=sum[i-1]+w[i];
    }

    for(int i=1;i<=m;++i)
        scanf("%d%d",&a[i].l,&a[i].r);
    sort(a+1,a+m+1,cmp);

    int tmp=1;
    for(int i=1;i<=n;++i)
    {
        while(i>a[tmp].r && tmp<=m)
            ++tmp;
        if(a[tmp].l<=i && i<=a[tmp].r)
            lef[i]=a[tmp].l;
    }

    for(int i=1;i<=n;++i)
    {
        if(lef[i]>0)
            for(int j=i;j>=lef[i];--j)
                f[i]=max(f[i],f[j-1]+sq(sum[i]-sum[j-1]));
        else
            f[i]=f[i-1];
    }
//  if(lef[n]!=0)
//      ans+=f[n];
    printf("%d\n",f[n]);

    return 0;
}

宗教

【SMOJ】2017.10.18模拟赛27_第4张图片
【SMOJ】2017.10.18模拟赛27_第5张图片

【分析】
正解后缀数组,利用height的特性,做RMQ,然后统计一下贡献。
说实话,关于字符串的题目本蒟蒻十分垃圾……

【代码】

#include
#include
#include
#include
using namespace std;

const int MAXN=(200000+5)*2;

int ans,n,s[MAXN],rmq[22][MAXN];
int sa[MAXN],c[MAXN],t[MAXN],t2[MAXN];
int rank[MAXN],height[MAXN],lg2[MAXN];
char a[MAXN],b[MAXN];

inline void get_sa(int m,int n)
{
    int *x=t,*y=t2;
    for(register int i=0;i<m;++i)
        c[i]=0;
    for(register int i=0;ix[i]=s[i];
        c[x[i]]++;
    }
    for(register int i=1;i<m;++i)
        c[i]+=c[i-1];
    for(register int i=n-1;i>=0;--i)
        sa[--c[x[i]]]=i;

    for(register int k=1;k<=n;k<<=1)
    {
        int p=0;
        for(register int i=n-k;iy[p++]=i;
        for(register int i=0;iif(sa[i]>=k)
                y[p++]=sa[i]-k;

        for(register int i=0;i<m;++i)
            c[i]=0;
        for(register int i=0;ix[y[i]]]++;
        for(register int i=0;i<m;++i)
            c[i]+=c[i-1];
        for(register int i=n-1;i>=0;--i)
            sa[--c[x[y[i]]]]=y[i];

        swap(x,y);
        p=1;x[sa[0]]=0;
        for(register int i=1;iif(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k])
                x[sa[i]]=p-1;
            else
                x[sa[i]]=p++;
        }
        if(p>=n)
            break;
        m=p;
    }
}

inline void get_height(int n)
{
    int j,k=0;
    for(register int i=0;i<=n;++i)
        rank[sa[i]]=i;
    for(register int i=0;iif(k)
            --k;
        j=sa[rank[i]-1];
        while(s[j+k]==s[i+k])
            ++k;
        height[rank[i]]=k;
    }
}

inline void get_rmq(int l,int r)
{
    for (register int i=l;i<=r;i++)
        rmq[0][i]=height[i+1];

    for (register int j=1;j<=20;j++)
    {
        for (register int i=0;i<=r-(1<q[j][i]=min(rmq[j-1][i],rmq[j-1][i+(1<<(j-1))]);
        }
    }
}

inline int RMQ(int aa,int bb)
{
    if (aa>bb) swap(aa,bb);
    int x=lg2[bb-aa];
    return min(rmq[x][aa],rmq[x][bb-(1<<x)]);
}

inline void presolve()
{
    lg2[0]=lg2[1]=0; 
    for (int i=2;i<=MAXN-10;i++)lg2[i]=lg2[i/2]+1;
}

int main()
{
    freopen("2257.in","r",stdin);
    freopen("2257.out","w",stdout);

    presolve();
    scanf("%s%s",a,b);
    int K;
    scanf("%d",&K);
    int lena=strlen(a),lenb=strlen(b);
    n=lena+lenb+1;

    for(register int i=0;is[i]=a[i];
    s[lena]=1;
    for(register int i=0;is[lena+i+1]=b[i];
    s[n]=0;

    get_sa('z'+1,n+1);
    get_height(n);
    get_rmq(0,n);

    ans=0;
    for (register int i=0;i1;i++)
    {
        int diff=0,pos=0;
        while (diff<=K&&posposint tmp=RMQ(rank[lena+1+pos],rank[pos+i]);
            if (tmp==0)
                diff++;
            else if (pos+tmppos+=tmp+1;
        }
        if (diff<=K)
            ans++;
    }
    printf("%d\n",ans);

    return 0;
}

完结睡觉~

你可能感兴趣的:(SMOJ模拟赛)