• 小魂和他的数列-(离散+二分+树状数组)


    https://ac.nowcoder.com/acm/problem/54585

    题意:给500000个数构成一个数列,求递增个数为k的子序列个数,2<=k<=10。

    题解:

    1.求递增子序列个数,子序列不是子串,可以散乱分布。原数组为a,排序后为数组b,遍历a数组,每次求得ai在数组b的下标位置,设为pos,在树状数组里对pos位置进行累加,维护k个树状数组,递增个数为j的子序列 需要 递增个数为j-1的子序列的数据。c[i][j]表示的递增个数为i的子序列在j这个位置的个数。

    2.一开始很难理解为什么要这样做,在纸上比划了许多下才懂,树状数组中还没有出现的值都是0,和逆序对有些相似。

    3.大量数据输入用Java解题需要自行封装输入模板

    import java.io.*;
    import java.util.StringTokenizer;
    import java.math.BigInteger;
    import java.util.Arrays;
    
    public class Main {
        static int [] a=new int[500010];
        static int [] b=new int[500010];
        static int [][] c=new int[11][500010];
        static int n=0;
        static int p=998244353;
        
        public static void main(String[] args) {
            InputStream inputStream = System.in;//InputStream是表示字节输入流的所有类的超类
            OutputStream outputStream = System.out;
            
            InputReader sc = new InputReader(inputStream);
            PrintWriter out = new PrintWriter(outputStream);
            
            Task solver = new Task();
            solver.solve(sc, out);//这里当作原来的Main函数,输入输出都在里面解决
            
            out.close();//关闭输出流
        }
     
        static class Task {    
            
            public void solve(InputReader scan, PrintWriter out) {
                n=scan.nextInt();
                int k=scan.nextInt();
                for(int i=1;i<=n;i++) {
                    a[i]=scan.nextInt();
                    b[i]=a[i];
                }
                Arrays.sort(b,1,n+1);            
                for(int i=1;i<=n;i++) {
                    int pos=check(1, n,a[i]);
                    //System.out.println("pos="+pos);
                    add(1, pos, 1);
                    for(int j=2;j<=Math.min(k, i);j++) {
                        add(j, pos, get_sum(j-1, pos-1));
                    }
                }
                System.out.println(get_sum(k, n));
                
                  
            }
            
            public static int lowbit(int x) {
                return (-x)&x;
            }
            
            public static void add(int i,int x,int val) {
                while(x<=n) {
                    c[i][x]=(c[i][x]+val)%p;
                    x=x+lowbit(x);
                }
                
            }
            
            public static int get_sum(int i,int x) {
                int res=0;
                while(x!=0) {
                    res=(res+c[i][x])%p;
                    x-=lowbit(x);
                }
                return res;
            }
            
            
            //二分 起始都是false,如果要找的x相同,先找一段相同的数的最左边,然后标记
            public static int check(int l,int r,int x) {
                int mid=-1;
                while(l<=r) {
                    mid=(l+r)/2;
                    //System.out.println("x="+x+" l="+l+" r="+r+" mid="+mid);
                    if(b[mid]>x) //往左
                        r=mid-1;
                    else if(b[mid]<x) //往右
                        l=mid+1;
                    else 
                        break;
                        
                }    
                return mid;
            }
        }
     
        
       //自己写出Scanner原本的输入语法,封装在InputReader类里
        static class InputReader {
            public BufferedReader reader;
            public StringTokenizer tokenizer;
            public InputReader(InputStream stream) {
                reader = new BufferedReader(new InputStreamReader(stream), 32768);
                //32768是输入缓冲区大小,随便设的
                tokenizer = null;
            }
     
            public String next() {
                while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                    try {
                        tokenizer = new StringTokenizer(reader.readLine());
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
                return tokenizer.nextToken();
            }
            
            public int nextInt() {
                return Integer.parseInt(next());
            }
     
            public long nextLong() {
                return Long.parseLong(next());
            }
            
            public double nextDouble() {
                return Double.parseDouble(next());
            }
    
            public boolean hasNext() {
                try {
                    String string = reader.readLine();
                    if (string == null) {
                        return false;
                    }
                    tokenizer = new StringTokenizer(string);
                    return tokenizer.hasMoreTokens();
                } catch (IOException e) {
                    return false;
                }
            }
            
            public BigInteger nextBigInteger() {//大数
                return new BigInteger(next());
            }
     
        }
    }
  • 相关阅读:
    Ping
    boost::python开发环境搭建
    mingw和libcurl
    ssh远程执行命令使用明文密码
    netty源码阅读之UnpooledByteBufAllocator
    Direct ByteBuffer学习
    clions的使用
    netty中的PlatformDependent
    STL之priority_queue(优先队列)
    c++线程调用python
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/12236151.html
Copyright © 2020-2023  润新知