zoukankan      html  css  js  c++  java
  • Codeforces 380A

    原题地址:http://codeforces.com/problemset/problem/380/A

    让期末考试整的好久没有写题, 放假之后由于生病也没怎么做,新年的第一场CF也不是那么在状态,只过了div2的前两道题,第三题想到算法但是太困了没写对,刚刚把第三题A了很兴奋,赶快过来把解题报告写了。不得不说这道题还算有点水平

    题目大意:

    维护一个初始为空的序列,支持两种操作,共 m 个(1 <= m <= 10 ^ 5):

    1 将一个数插入到数列的尾端(插入的数不大于10 ^ 5)

    2 将数列的前 l 位复制 c 次,贴到数列的尾端(1 <= l <= 10 ^ 5, 1 <= c <= 10 ^ 4)

    然后进行 n (1 <= n <= 10 ^ 5)次查询,每次给出一个数 x ,输出最终数列的第x位(所有查询数满足严格递增)

    题目满足数据合法

    题目分析:

    这道题给人的第一反应是数据规模很大,直接模拟生成数列不仅会超时,而且会爆系统内存(最多大概可以有 10 ^ 9个数),所以我们着手去想其他的解题思路。

    首先想到的是处理出每一个操作所生成的数列的位置(包括起始位置和终止位置)然后按照查询给出的位置 x 在操作序列中二分查找出生成包含 x 这一段的操作的位置,根据这个操作去计算位置x上的值。但是这样要考虑到一件事,如果生成 x 的操作是操作 2 , 那么由于操作 2 是复制当前数列的前l个数,而当前数列仍旧是未知的,也就是说我们还是需要再在前面的操作中二分,知道查到一个由操作一生成的点。这种做法直接导致复杂度无法估计,而且递归的编程难度加大,想法有点难实现。

    接下来我们从范围入手,注意到操作二只会用到当前数列的前10 ^ 5个点,而数列中的点是不会修改的,所以我们萌生了这种想法:模拟出数列的前10 ^ 5个点,然后再查找生成 x 的对应操作。这样问题就简化很多了。

    模拟之后的查找有两种方案,第一种还是二分,复杂度O(n log n)没问题,但是写起来稍微麻烦。后一种方法用到了题目中查询序列的递增顺序,直接线性地从先往后扫就行,复杂度是O(n + m)

    细节处理:

    1. 注意边界条件和循环退出条件

    2.如果当前查到的点的位置小于10 ^ 5 直接输出模拟出来的数列中的对应位置值就可以了。

    3.如果查到的位置对应操作为操作1,直接输出操作一的操作数值,如果为操作二需要计算一下取模(详见代码),特别注意取模得零的情况

     1 //date 20140114
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 
     6 using namespace std;
     7 
     8 const int maxm = 100005;
     9 
    10 inline int getint()
    11 {
    12     int ans(0); char w = getchar();
    13     while('0' > w || w > '9')w = getchar();
    14     while('0' <= w && w <= '9')
    15     {
    16         ans = ans * 10 + w - '0';
    17         w = getchar();
    18     }
    19     return ans;
    20 }
    21 
    22 int n, m;
    23 struct build
    24 {
    25     int ord, x, l, c;
    26     long long a, b;
    27 }hell[maxm];
    28 int sq[maxm];
    29 
    30 int main()
    31 {
    32     m = getint();
    33     for(int i = 1; i <= m; ++i)
    34     {
    35         hell[i].ord = getint();
    36         if(hell[i].ord == 1){
    37             hell[i].x = getint(); 
    38             hell[i].a = hell[i].b = hell[i - 1].b + 1LL;
    39             if(hell[i].a < maxm)sq[hell[i].a] = hell[i].x;
    40         }
    41         else{
    42             hell[i].l = getint(); hell[i].c = getint();
    43             hell[i].a = hell[i - 1].b + 1LL;
    44             hell[i].b = hell[i - 1].b + (long long)hell[i].l * (long long)hell[i].c;
    45             if(hell[i].a < maxm)
    46             {
    47                 int now = hell[i].a;
    48                 for(int j = 1; j <= hell[i].c && now < maxm; ++j)
    49                     for(int k = 1; k <= hell[i].l && now < maxm; ++k)
    50                         sq[now++] = sq[k];
    51             }
    52         }
    53     }
    54     
    55     n = getint();
    56     int h = 1; long long x;
    57     for(int i = 1; i <= n; ++i)
    58     {
    59         cin >> x;
    60         while(!(hell[h].a <= x && hell[h].b >= x))++h;
    61         if(x <= 100000)printf("%d ", sq[x]);
    62         else{
    63             if((x - hell[h - 1].b) % (long long)hell[h].l != 0)
    64                 cout << sq[(x - hell[h - 1].b) % (long long)hell[h].l] << ' ';
    65             else cout << sq[hell[h].l] << ' ';
    66         }
    67     }
    68     return 0;
    69 }

    总结:

    这题就是想法和细节以及编程能力。

  • 相关阅读:
    设计模式笔记4(工厂模式)
    设计模式笔记4(工厂模式)
    以前写的东东,放在这里个索引吧
    sicily 1001. Black Magic
    沙漠之旅
    hdu 1395(2^x mod n = 1)
    hdu 2161(Primes)
    sicily 8058. Matrix
    十进制转换为二进制
    硬币水题II
  • 原文地址:https://www.cnblogs.com/w007878/p/3519176.html
Copyright © 2011-2022 走看看