zoukankan      html  css  js  c++  java
  • 2021“MINIEYE杯”中国大学生算法设计超级联赛(10)

    2021“MINIEYE杯”中国大学生算法设计超级联赛(10)

    庆祝暑期训练赛结束了

    Pty loves lines

    • 题意

    (n)条直线,求直线相交的所有可能的交点数情况并输出。

    • 思路

    首先,每条直线最极端情况(所有直线不平行),那么就有(frac{(n * (n - 1))}{2})个交点。
    之后,我们先管直线的平行情况。

    1. 所有直线相交,即0(所有(n)都存在的一种情况)
    2. (n - 1)条直线平行,即(1 * (n - 1) = n - 1),一种
    3. (n - 2)条直线平行,那么另外两条直线可以平行,也可以相交,那么答案为: (2 * (n - 2) + 0 or 2 * (n - 2) + 1)两种。
    4. (n - 3)条直线平行,那么看另外三条直线((0,2,3) + (3 * (n - 3)))
      之后其实都差不多,那么我们也可以发现第四种情况的时候,看另外三条直线的情况,其实左边那部分就是(n = 3)时的情况,后面在推也一样,那么通过这个性质就可以求递推公式,然后用(dp)进行状态转移即可。
      定义(f[i][j])表示(i)条直线,(j)个交点的情况是否可以,((f[i][j])为1或0),那么(f[i][j] = f[i - k][j + (k * (i - k))]),就类似我上面的递推,然后(O(n^4))打表程序就出来了0.0,其实我们发现这个性质后就应该想到可以用bitset加一层优化,然后通过打表可以发现,一大段数字在后面都是连续的不用管(最多在30000多那就一直连续了,这个连续的最大值也可以打表求出来),那么就可以直接暴力点不管那后面的,那么就可以随便跑了(O(n * n * 32000 / w))

    code :

    const int N = 710, M = 32000;
    
    bitset<M> f[N];
    
    void init() {
        f[0][0] = 1;
        fep(i,1,700) {
            fep(k,1,i) {
                f[i] |= f[i - k] << (k * (i - k));
            }
        }
    }
    
    void solve(){
        int n;
        cin >> n;
        int limit = min(M - 1, n * (n - 1) / 2);
        bool flag = 0;
        for(int i = 0;i <= limit;i ++){
            if(f[n][i]) {
                if(flag) cout << ' ';
                else flag = 1; 
                cout << i;
            } 
        }  
        for(int i = limit + 1;i <= (n * (n - 1) / 2);i ++) {
            cout << ' ' << i;
        }
        cout << endl;
    }
    

    Pty loves string

    • 题意

    给一个字符串(S),共(Q)次询问,问字符串(S)中长度为(l)的前缀 + 长度为(r)的后缀形成的字符串在(S)中出现的次数。

    • 思路

    (kmp)找到字符串中长度相同的子串,前后都跑一边,那么长度为(l),到某个点(x)(1 o l = x o x + l - 1),点y,(n - r o n = y - r + 1 o y),然后就是判断(y - r + 1 = x + l)的点即可,然后就是找一点(z)(1 o l = z - l + 1 o z and n - r o n = z o z + r - 1),存在即答案加1,可以看出建图跑比较方便。
    然后建两棵树的图即可,随意用一颗树的dfs序在另一颗树上跑主席树,可持久化记忆。然后每次查询即可

    code :

    int in[N][2], out[N][2], tot[2], pos[N];
    int rt[N];
    int ls[N << 8],rs[N << 8],sum[N << 8], idx;
    char str[N];
    int f1[N],f2[N];
    int kkk;
    int h1[N],e1[N],ne1[N],m1, h2[N], e2[N],ne2[N], m2;
    
    void ad1(int a,int b) {
        e1[m1] = b, ne1[m1] = h1[a], h1[a] = m1 ++;
    }
    
    void ad2(int a,int b) {
        e2[m2] = b, ne2[m2] = h2[a], h2[a] = m2 ++;
    }
    void dfs1(int u)
    {
        in[u][0] = ++ tot[0];
        pos[tot[0]] = u;
        for(int i = h1[u];~i;i = ne1[i]) {
            int j = e1[i];
            dfs1(j);
        }
        out[u][0] = tot[0];
    }
    void dfs2(int u) {
        in[u][1] = ++ tot[1];
        for(int i = h2[u];~i;i = ne2[i]) {
            int j = e2[i];
            dfs2(j);
        }
        out[u][1] = tot[1];
    }
    
    void insert(int &t,int pre,int l,int r,int x) {
        t = ++ idx;
        ls[t] = ls[pre]; rs[t] = rs[pre];
        sum[t] = sum[pre] + 1;
        if(l == r) {return;}
        int mid = l + r >> 1;
        if(x <= mid) insert(ls[t],ls[pre],l,mid,x);
        else insert(rs[t],rs[pre],mid + 1,r,x);
    }
    
    int query(int p,int q,int l,int r,int x,int y) {
        if(r < x || y < l) return 0;
        if(x <= l && r <= y) return sum[p] - sum[q];
        int mid = l + r >> 1;
        return query(ls[p],ls[q],l,mid,x,y) + query(rs[p],rs[q],mid + 1,r,x,y);
    }
    
    void solve(){
        int n,q;
        cin >> n >> q;
        cin >> (str + 1);
        // 字符串kmp预处理
        int j = 0;
        memset(h1,-1,sizeof h1);
        memset(h2,-1,sizeof h2);
        for(int i = 2;i <= n;i ++) {
            while(j && str[j + 1] != str[i]) j = f1[j];
            if(str[j + 1] == str[i]) j ++;
            f1[i] = j;
        }
        j = n + 1;
        f2[n] = n + 1;
        for(int i = n - 1;i >= 1;i --) {
            while(j <= n && str[j - 1] != str[i]) j = f2[j];
            if(str[j - 1] == str[i]) j --;
            f2[i] = j;
        }
        // 建树
        for(int i = 1;i <= n;i ++) {
            ad1(f1[i],i);
            ad2(f2[i],i);
        }
        dfs1(0);
        dfs2(n + 1);
        // 处理
        for(int i = 1;i <= n + 1;i ++) { // 注意我们的dfs序是从0或n + 1开始的,所以需要加1
            insert(rt[i], rt[i - 1],1,n + 1,in[pos[i] + 1][1]);
        }
        while(q --) {
            int x,y;
            cin >> x >> y;
            y = n - y + 1;
            cout << query(rt[out[x][0]],rt[in[x][0] - 1],1,n + 1,in[y][1],out[y][1]) << endl;
        }
        for(int i = 0;i <= n + 1;i ++) f1[i] = f2[i] = 0, rt[i] = 0;
        idx = tot[1] = tot[0] = 0;
        m1 = m2 = 0;
    }
    
    
  • 相关阅读:
    ubuntu下如何批量修改文件后缀名
    vanilla
    Ubuntu apt-get 彻底卸载软件包
    Kendall Rank(肯德尔等级)相关系数
    图像质量评估(IQA)
    conda常用命令
    在ubuntu中搜索文件或文件夹的方法
    libstdc++.so.6: version `GLIBCXX_3.4.21' not found
    迅雷磁力链接转BT种子工具
    springboot 集成mybatis plus3
  • 原文地址:https://www.cnblogs.com/darker-wxl/p/15165963.html
Copyright © 2011-2022 走看看