zoukankan      html  css  js  c++  java
  • 2020 2.6

    t1

    题意,用一个错误算法求逆序对,当前数为p[i]则daan+=max(0,i-p[i]);现在有n个数为1-n的排列,已经给出了前m个数,求有好多种排列方法使得该算法答案正确。

    题解。

    发现如果当前p[i]<=i则要求前面的所有内容都比他小,否则p[i]>i,则要求比他小的的内容全部在他前面,否则加少了。

    设f[i][j]表示已经放完了前i个位置,最大的数是j的方案数。可知j>=i。

    若j>=i则必能找到一个最小的值放进来f[i][j]+=f[i-1][j]。

    考虑放一个大的值j,枚举比这个值小的k。f[i][j]+=f[i-1][k]。

    先把已经给出的数预处理好在这样转移即可。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=205;
    const int mo=1e9+7;
    int T,a[N],f[N][N],n;
    bool book[N];
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    int main()
    {
        T=read();
        while(T--)
        {
            n=read();int m=read();
            memset(a,0,sizeof(a));
            memset(f,0,sizeof(f));f[0][0]=1;
            memset(book,0,sizeof(book));
            int xiao=1;
            for(int i=1;i<=m;i++) a[i]=read();
            for(int i=1;i<=n;i++)
            {
                if(a[i])
                {
                    for(int j=0;j<a[i];j++)
                        f[i][a[i]]=(f[i][a[i]]+f[i-1][j])%mo;
                    if(xiao==a[i])
                        for(int j=max(i,a[i]+1);j<=n;j++)    
                            f[i][j]=(f[i][j]+f[i-1][j])%mo;
                    book[a[i]]=1;
                    while(xiao<=n&&book[xiao]==1) xiao++;
                }
                else
                {
                    for(int k=1;k<=n;k++)
                        for(int j=0;j<k;j++)
                            f[i][k]=(f[i][k]+f[i-1][j])%mo;
                    for(int j=i;j<=n;j++)
                        f[i][j]=(f[i][j]+f[i-1][j])%mo;
                }
            }
            cout<<f[n][n]<<"
    ";
        }
    }
    View Code

    t2

    题意:给出一个字符串,将他的所有子串按字典序排列,q次询问每次询问新串的第k个字符是什么,强制在线。

    题解:

    使用后缀数组。

    先求出height然后将每个后缀分割成几部分顺序加入新串,表示有这一段,重复了几次,从哪儿开头。

    求出长度的前缀和然后二分查找出在哪一段,再二分查找出在这一段的哪里即可。

    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=2e6+5;
    int sa[N],rk[N],n,x[N],y[N],height[N],tong[N],m=135;
    char c[N];
    struct pigu
    {
        int l,r,cnt,pos;
        inline int tot()
        {
            return (l+r)*(r-l+1)/2*cnt;
        }
        inline int query(int cha)
        {
            int lq=l,rq=r,daan=l-1;
            while(lq<=rq) 
            {
                  int mid=(lq+rq)>>1;
                  if(((1ll*(l+mid)*(mid-l+1))>>1)*cnt<cha) 
                daan=mid,lq=mid+1;
                  else rq=mid-1;
            }
            return pos+(cha-((1ll*(l+daan)*(daan-l+1))>>1)*cnt-1)%(daan+1);
        }
    }q[N];
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    inline void get_sa()
    {
        for(int i=1;i<=n;i++) x[i]=c[i],tong[x[i]]++;
        for(int i=1;i<=m;i++) tong[i]+=tong[i-1];
        for(int i=n;i>=1;i--) sa[tong[x[i]]--]=i;
        for(int k=1;k<=n;k<<=1)
        {
            int cnt=0;
            for(int i=n-k+1;i<=n;i++) y[++cnt]=i;
            for(int i=1;i<=n;i++) if(sa[i]>k) y[++cnt]=sa[i]-k;
            memset(tong,0,sizeof(tong));
            for(int i=1;i<=n;i++) tong[x[i]]++;
            for(int i=1;i<=m;i++) tong[i]+=tong[i-1];
            for(int i=n;i>=1;i--) sa[tong[x[y[i]]]--]=y[i];
            memset(y,0,sizeof(y));
            swap(x,y);cnt=0;x[sa[1]]=cnt=1;
            for(int i=2;i<=n;i++)
            {
                if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) cnt++;
                x[sa[i]]=cnt;
            }
            if(cnt==n) break;m=cnt;
        }
        for(int i=1;i<=n;i++) rk[sa[i]]=i;
        int dao=0;
        for(int i=1;i<=n;i++)
        {
            if(rk[i]==1) continue;
            if(dao) dao--;
            int hu=sa[rk[i]-1];
            while(c[i+dao]==c[hu+dao]) dao++;
            height[rk[i]]=dao;
        }
    }
    int pos[N],id[N],cnt1,sum[N];
    inline void init()
    {
        int top=0;pos[0]=-1;id[0]=id[1]=n+1;
        for(int i=n;i>=1;i--)
        {
            int now=n-sa[i]+1;
            if(now==pos[top]) top--;
            while(height[i]<=pos[top])
            {
                q[++cnt1]=(pigu){pos[top]+1,now,id[top]-i,sa[i]};
                now=pos[top];
                top--;
            }
            if(height[i]<now) q[++cnt1]=(pigu){height[i]+1,now,id[top]-i,sa[i]};
            top++;pos[top]=height[i];id[top]=i;
        }
        for(int i=1;i<=cnt1/2;i++) swap(q[i],q[cnt1-i+1]);
        for(int i=1;i<=cnt1;i++) sum[i]=sum[i-1]+q[i].tot();
        int Q=read(),su=0;
        while(Q--)
        {
            int a=read(),b=read();
            a=(a*su)%b;a++;
            int now=lower_bound(sum+1,sum+cnt1+1,a)-sum;
            now=q[now].query(a-sum[now-1]);
            cout<<c[now]<<"
    ";
            su+=c[now];
        }
    }
    signed main()
    {
        scanf("%s",c+1);
        n=strlen(c+1);
        get_sa();
        init();
    }
    View Code
  • 相关阅读:
    转载 自定义ListView背景
    Android 在模拟器上创建sd卡
    转载 Android TextView加下划线
    转载 Dom4j生成xml
    转载 在Struts2中使用servlet 配置问题
    android开发不错的地方
    bat demo1自定义变量
    redhat 5下安装SVN
    linux 忘记root密码
    DEBUG Sigar no libsigarx86linux.so in java.library.path
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12271440.html
Copyright © 2011-2022 走看看