zoukankan      html  css  js  c++  java
  • 【AtCoder Regular Contest 082 F】Sandglass

    【链接】点击打开链接


    【题意】


    你有一个沙漏。
    沙漏里面总共有X单位的沙子.
    沙漏分A,B上下两个部分。
    沙漏从上半部分漏沙子到下半部分。
    每个时间单位漏1单位的沙子。
    一开始A部分在上面。然后在r1,r2,....rk时刻,会把沙漏翻转一下.
    给你Q个询问,每个询问两个数字ti,ai;
    表示一开始A部分有ai个单位的沙子,问你ti时刻,A部分有多少沙子。

    【题解】


    我们设f[i]表示初始A部分有i个单位的沙子,t时刻A中剩余的沙子数目,并假设X=7;
    我们先来模拟一下这个过程,右边的加号和减号表示沙子增加或减少(对应A在漏或在接沙子)
    t=0 f[] = {0,1,2,3,4,5,6,7}
    t=1 f[] = {1,2,3,4,5,6,7,7} +
    t=2 f[] = {2,3,4,5,6,7,7,7} +
    t=3 f[] = {3,4,5,6,7,7,7,7} +
    t=4 f[] = {2,3,4,5,6,6,6,6} -
    t=5 f[] = {1,2,3,4,5,5,5,5} -
    t=6 f[] = {0,1,2,3,4,4,4,4} -
    t=7 f[] = {0,0,1,2,3,3,3,3} -
    t=8 f[] = {1,1,2,3,4,4,4,4} +
    可以看到,f数组总是类似{a,a,a+1,a+2,a+3...b-2,b-1,b,b}这样的形式;
    a和b会随着沙子减少或增加的时候发生改变.
    而且变化都是有规律的,因为每个数字都递增1或递减1.
    那么,如果我们能维护a和b的位置l和r的话,就能很容易得到答案了.
    如果初始沙子ai<=l,则答案为a,如果ai >= r则答案为b,否则为a + ai - l;
    我们可以按照ri的时间,一块一块地获取到ri时刻f数组的四个参数a,b,l,r;
    (因为r[i-1]..r[i]这一段肯定都是减,或都是加,那么想要维护a,b,l,r就不会难了)
    (只有在a减去时间差小于0或是b加上时间差大于X的时候,l和r才会变)
    然后对于询问ti,ai,我们只要找到最大的j,使得rj <= ti;
    这样,我们先通过rj时刻f数组的参数a,b,l,r来获取初始沙子量为ai,rj时刻A的沙子量temp.
    然后rj..ti这一段则全是减或全是加,则temp直接加上或减去ti-rj就可以了,大于X则变成X,小于0则变成0.
    做的时候,可以把询问和翻转操作的时间放在一起,然后排个序.
    翻转操作,就维护a,b,l,r;如果是询问操作,就通过a,b,l,r求出初始沙子量为ai,时刻前一个翻转点A的沙子量temp.
    再加上ti-前一个反转点的时间就是所需的答案了。


    【错的次数】


    1

    【反思】


    初始沙子量为0..X;
    然后时间为t时,对应沙子量随着t的递增,是有规律的.
    因为每种初始沙子量,它随着时间,在某个区间内都是递增1,或都是递减1.
    这样,在整块都是递减,或整块都是递增的时间里,我们能快速维护,初始沙子量为0..X,对应时间的沙子量.
    (不用求出来,只要通过维护4个变量就能O(1)处理询问);
    虽然询问是单点的.
    但只要能快速求出它前一个翻转的时间点,剩下的也能O(1)处理.
    翻转的时间点之间就是整块的加或整块减的时间。
    如果只有一个初始的沙子量,那么这题就是一道水题了。
    但是因为多个沙子量,给实现造成了很大的困难.
    因此通过模拟,发现初始沙子量不同的话,到某个时刻的沙子量是有规律的。
    从而解决了有多个初始沙子量的问题。

    【代码】

    /*
    
    */
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <set>
    #include <cstdlib>
    #include <cmath>
    #include <bitset>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb emplace_back
    #define fi first
    #define se second
    #define ld long double
    #define ms(x,y) memset(x,y,sizeof x)
    #define ri(x) scanf("%d",&x)
    #define rl(x) scanf("%lld",&x)
    #define rs(x) scanf("%s",x)
    #define rf(x) scnaf("%lf",&x)
    #define oi(x) printf("%d",x)
    #define ol(x) printf("%lld",x)
    #define oc putchar(' ')
    #define os(x) printf(x)
    #define all(x) x.begin(),x.end()
    #define Open() freopen("F:\rush.txt","r",stdin)
    #define Close() ios::sync_with_stdio(0)
    #define sz(x) ((int) x.size())
    #define ld long double
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    //mt19937 myrand(time(0));
    //int get_rand(int n){return myrand()%n + 1;}
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int N = 2e5;
    
    struct abc{
        int t,a,id;
        bool operator < (const abc & tmp) const{
            return t < tmp.t;
        }
    };
    
    int X,K,n,ans[N+10];
    abc q[N+10];
    
    int main(){
        //Open();
        //Close();
        ri(X),ri(K);
        rep1(i,1,K) {
            int x;
            ri(x);
            q[++n].t = x;
        }
        ri(K);
        rep1(i,1,K){
            int t,a;
            ri(t),ri(a);
            q[++n].t = t,q[n].a = a,q[n].id = i;
        }
        sort(q+1,q+1+n);
        int a = 0,b = X,l = 0,r = X,pre = 0,sign = -1;
        rep1(i,1,n)
            if (q[i].id){
                //是一个询问
                int rest = q[i].t - pre,temp;
                if (q[i].a <= l){
                    temp = a;
                }else if (q[i].a >= r){
                            temp = b;
                      }else
                            temp = a + q[i].a - l;
                temp += sign*rest;
                if (temp > X) temp = X;
                if (temp < 0) temp = 0;
                ans[q[i].id] = temp;
            }else{
                //是一个翻转操作
                int v = q[i].t - pre;
                if (sign==-1){//如果要做减法
                    if (a<v){//如果最小的那个不够减了,则肯定
                        b = max(b-v,0);
                        l = min(l + (v-a),X);
                        r = max(l,r);
                        a = 0;
                    }else{
                        a-=v,b-=v;
                    }
                }else{
                    if (b+v<=X){//最大的加上v之后都小于等于X则可行,a+v<=x,a+1+v<=x...a+b-a+v<=x
                        a+=v,b+=v;
                    }else{
                        //b+v>X
                        a = min(a+v,X);//a加上之后可能大于X了.最大让他为X
                        r = max(r - (b+v-X),0);//倒数第1+(b+v-X)个数到最后一个数都变成X了
                        l = min(l,r);//r要是小于l了,就把l变成r就好.
                        b = X;//b是肯定变成x了
                    }
                }
                pre = q[i].t;
                sign = sign*(-1);
            }
        rep1(i,1,K)
            oi(ans[i]),puts("");
        return 0;
    }
    
    


  • 相关阅读:
    使用Arduino和加速度计自制计步器
    使用MPU6050陀螺仪自制Arduino数字量角器
    使用Arduino和SD卡模块记录数据并导出到Excel
    NUCLEO-8L152开发板中文应用笔记整理集合
    使用Arduino开发板连接干簧管(Reed Switch)的方法
    MSP430 LaunchPad开发板入门教程集合
    使用Arduino开发板和ESP8266从互联网读取数据
    使用Arduino开发板实现与MPU6050陀螺仪传感器连接的方法
    使用Arduino和LED光柱显示器件轻松制作电池电压指示器
    JDK和JRE的区别
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626052.html
Copyright © 2011-2022 走看看