zoukankan      html  css  js  c++  java
  • 两道来自CF的题

    本菜鸟又在CF Div2水了一次,这次的5道题只做出了两道,Div2的C,D(Div1的A,B),不错的题目,可惜当时只想到了一半半,要继续修炼呀。

         题意是这样的,给定两个串s1,s2,s1可以使用多次,拼成s1s1s1…s1这种串,然后去掉任意多个字母能变成s2,问说最少用多少个s1。

         暴力的思路比较好想,在s1,s2上设立两个指针,都是单向的,相应进行匹配,如果s1处的指针走满后,就另起一个,但这样的复杂度是O(ans*|s1|),主要的开销在于s1上的指针每次都要走来走去的,因为字典就a…z这26种,每次找过的a,又得重新再找一遍,太冗余了,可以用dp(i, j)记录从i…len(s1)这个串中,最左边的字母j的位置,这样就可以快速定位i指针的位置了。预处理dp(i, j)的时间复杂度是O(26*|s1|),总的复杂度为O(26*|s1| + |s2|),这样的复杂度就可以AC了,也可以这样优化,建立26个有序表,然后二分快速定位相应的位置,这样的话可以把复杂度降为O(|s1| + |s2| * log|s2|),补充一句,题解说可以用B树优化。代码如下:

    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <vector>
    #include <map>
    using namespace std;
     
    const int MAX = 1e4 + 5;
     
    string s1, s2;
     
    int d[MAX][26];    //d[i][j]表示从s1[i],s1[i+1],...,s1[len(s1)]中最左边的i在哪里
     
    int main()
    {
        cin >> s1 >> s2;
        int i;
        int len1 = s1.length();
        int len2 = s2.length();
     
        memset(d, -1, sizeof(d));
        for(i = len1 - 1; i >= 0; i--)
        {
            for(int j = 0; j < 26; j++)  d[i][j] = d[i + 1][j];
            d[i][s1[i] - 'a'] = i;
        }
     
        i = 0;
        int ans = 0, j = 0;
        while(j < len2)
        {
            if(d[i][s2[j] - 'a'] != -1)
            {
                i = d[i][s2[j] - 'a'] + 1;
                j++;
            }
            else
            {
                if(i == 0)  break;
                ans++;
                i = 0;
            }
        }
     
        if(j < len2)  cout << "-1";
        else  cout << ans + 1;
    }

         题意是这样的,N个整数组成一个序列,用a1, a2, …, an表示,对于每个每个位置i,求出i右边,最远的j使得aj < ai。题解的方法很巧妙,建立数组m[],m[i]表示从ai到an中的最小值,则m[i]是个递减数组,然后枚举的时候,二分逼近那个最远的边界就可以了,复杂度是O(N*logN),有人提到先对数组排序后,然后枚举,并保存最远的位置,也是个不错的方法,但要注意数组中的值可能相等,复杂度也是O(N*logN)。前者方法的代码如下:

    #include <iostream>
    #include <string>
    #include <set>
    #include <vector>
    #include <map>
    using namespace std;
     
    const int MAX = 1e5 + 5;
     
    int v[MAX], r[MAX], m[MAX], n;
     
    int main()
    {
        cin >> n;
        for(int i = 1; i <= n; i++)
            cin >> v[i];
     
        r[n] = n;  m[n] = v[n];
        for(int i = n - 1; i >= 1; i--)
        {
            m[i] = min(m[i + 1], v[i]);
     
            int low = i, high = n;
            while(low <= high)
            {
                int mid = (low + high) / 2;
                if(m[mid] < v[i])  low = mid + 1;
                else  high = mid - 1;
            }
     
            if(high >= i)  r[i] = high;
            else  r[i] = i;
        }
     
        for(int i = 1; i <= n; i++)
            cout << r[i] - i - 1 << " ";
    }
  • 相关阅读:
    记解决一次“HTTP Error 400. The request URL is invalid”的错误
    微信退款时候报”请求被中止: 未能创建 SSL/TLS 安全通道“或”The request was aborted: Could not create SSL/TLS secure channel“的错误
    aps.net国际化本地资源 .resources”正确嵌入或链接到程序集
    远程链接 aws Windows Server 2016 Base Nano
    linux odbc框架
    linux webservice
    linux 共享内存管理
    linux 广播寻址
    linux curse库
    linux log框架设计
  • 原文地址:https://www.cnblogs.com/litstrong/p/2088424.html
Copyright © 2011-2022 走看看