CSP-S模拟4

考大原题不会做!?我好无语啊……好像还是我为数不多的对着文字版题解自己改的那个(所以才只有70分),好在记住了个m=0,但是上次都能写对的暴力分给写错了***

既然他想帮他引流,我也帮个忙好了-> 题解

中秋节过去了,满月正在走向缺月,我们也正在走向NOIP……

忽然想到了虎哥擦掉4机房黑板的场景,当“hzoi2020 forever”因为hzoi 2021的到来而烟消云散,那种画面竟有着震撼人心的力量——有一天我们也会嘴上说着永远而后天各一方,有一天我们会无奈的承认青春它就是会散场,哪有什么岁月漫长,有的可能只是光阴荏苒物是人非你十年饮冰空自热血难凉……

为什么要卷啊?为什么不卷啊!只是想把我一生中最珍贵最美好的时光,放在我最喜爱最留恋的地方,哪怕没有希望,也要相信希望;如果没有太阳,我就要成为微光!

 

A. 石子游戏

对于一个连暴力 TLE 50 的做法都看不懂的题,大概只能咕了……

 

B. 大鱼吃小鱼

当你发现你想用set找前驱写了个set却怎么都过不了编译的时候……于是就搞了一棵带旋转的Treap,至少调了俩小时……啊我要是再忘了set的用法我就***

虽然正解是线段树,但是当我听说平衡树能对并且更好理解的时候,我就去学习了一下无旋Treap,不过到最后也就抄了个 MLE 74 不知道为啥……

upd:后来我又copy了一下Chen_jr的代码然后就A了*

直接引用Delov的博客:

贪心吃当且能吃的最大的显然是对的,假设一条一条的吃,吃到某个时候,我们能吃更大的了,这时候我们一定会去吃这个更大的,于是我们可以考虑模拟这个过程。暴力的话就是拿个map维护所有鱼,然后按从小到大枚举,同时维护一个当且能吃的鱼的集合,我们每次考虑从能吃的里吃掉一些,使得我们能够扩大能吃的鱼的集合,或者先一步达到要求。暴力就是不断选最大的吃,但是显然每次我们吃的都是一段后缀,于是我们可以二分找到这一段一次性吃掉,然后我们就可以吃更大的鱼了。考虑当前体积为now,比now大的最小的鱼体积为x,我们可以一只log的复杂度达到大于x的体积,这时候我们可以吃x了,由于x>now,于是我们的体积翻倍,显然最多只会吃log次,复杂度两只log。

关于实现的话,线段树离散化之类的很难写,考虑用FHQ_Treap,每次把要吃掉的Split出来,剩下的合并然后递归处理,回溯的时候在按原来Split的界Split开,把吃掉的merge回去,就能复原了。

code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 4e5 + 4;
const int N = 505;
const ll INF = 1e18 + 1e5;

int n, q;

inline ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct FHQ_Treap 
{
    #define ls t[x].l
    #define rs t[x].r
    struct node 
    {
        ll val, sum;
        int l, r, size, key;
    }t[maxn];
    int root, tot;
    int New(ll val)
    {
        t[++tot].key = rand();
        t[tot].val = t[tot].sum = val;
        t[tot].size = 1;
        return tot;
    }
    void pushup(int x)
    {
        t[x].sum = t[ls].sum + t[rs].sum + t[x].val;
        t[x].size = t[ls].size + t[rs].size + 1;
    }
    void split(int x, int &l, int &r, ll val)
    {
        if(!x) return l = r = 0, void();
        if(val < t[x].val) {split(t[x].l, l, t[x].l, val); r = x;}
        else {split(t[x].r, t[x].r, r, val); l = x;}
        pushup(x);
    }
    void split_sum(int x, int &l, int &r, ll sum)
    {
        if(!x) return l = r = 0, void();
        if(t[rs].sum >= sum) {split_sum(rs, rs, r, sum); l = x; pushup(x); return;}
        if(t[rs].sum+t[x].val >= sum) {l = ls; r = x; t[x].l = 0; pushup(x); return;}
        split_sum(ls, l, ls, sum-t[rs].sum-t[x].val);
        r = x; pushup(x);
    }
    int merge(int x, int y)
    {
        if(!x || !y) return x | y;
        if(t[x].key < t[y].key) {t[x].r = merge(t[x].r, y); pushup(x); return x;}
        else {t[y].l = merge(x, t[y].l); pushup(y); return y;}
    }
    void insert(ll val)
    {
        int l = 0, r = 0; split(root, l, r, val);
        root = merge(merge(l, New(val)), r);
    }
    void erase(ll val)
    {
        int l = 0, m = 0, r = 0; split(root, l, r, val); split(l, l, m, val-1);
        m = merge(t[m].l, t[m].r);
        root = merge(merge(l, m), r);
    }
    ll findmin(int x)
    {
        if(x == 0) return INF;
        while(t[x].l) {x = t[x].l;}
        return t[x].val;
    }
    int solve(ll s, ll k)
    {
        if(s > k) return 0;
        int l = 0, m = 0, r = 0;
        split(root, l, r, s-1);
        ll nxt = min(findmin(r), k);
        if(s + t[l].sum <= nxt)
        {
            root = merge(l, r);
            return -1;
        }
        split_sum(l, l, m, nxt-s+1);
        root = merge(l, r);
        int ans = t[m].size;
        int down = solve(s+t[m].sum, k);
        l = r = 0;
        split(root, l, r, s-1);
        root = merge(merge(l,m), r);
        if(down == -1) return -1;
        return ans + down;
    }
}t;

int main()
{
    freopen("fish.in", "r", stdin);
    freopen("fish.out", "w", stdout);
    
    n = read();
    for(int i=1; i<=n; i++)
    {
        t.insert(read());
    }
    q = read();
    for(int i=1; i<=q; i++)
    {
        int op = read();
        if(op == 1)
        {
            ll s = read(), k = read();
            printf("%d\n", t.solve(s, k-1));
        }
        if(op == 2) t.insert(read());
        if(op == 3) t.erase(read());
    }

    return 0;
}

 

C. 黑客

好像不是第一次遇到这种 换个角度枚举就是正解 的题,比如结果的情况比产生结果的方式枚举的次数小很多。

求那个范围时直接除法就好了,我一开始还打算二分***还没写对***

code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5e5 + 3;
const ll mod = 1e9 + 7;
const int INF = 0x7fffffff; 

ll A, B, C, D, ans;

inline ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

inline void check(ll a, ll b)
{
    ll k1 = ceil((double)A/a), k2 = (double)B/a;
    ll k3 = ceil((double)C/b), k4 = (double)D/b;
    k1 = max(k1, k3); k2 = min(k2, k4);
    if(k1 > k2) return;
    ans = (ans + (k2-k1+1)*(a+b)%mod) % mod;
}

inline ll gcd(ll a, ll b)
{
	while(b^=a^=b^=a%=b);
	return a;
}

int main()
{  
    freopen("hacker.in", "r", stdin);
    freopen("hacker.out", "w", stdout);

    A = read(); B = read(); C = read(); D = read();
    for(int i=1; i<=999; i++)
    {
        for(int j=1; j<=999-i; j++)
        {
            if(gcd(i, j) != 1ll) continue;
			check(i, j);
            /*ll k1 = ceill((double)A/i), k2 = B/i;
            ll k3 = ceill((double)C/j), k4 = D/j;
            k1 = max(k1, k3); k2 = min(k2, k4);
            if(k1 > k2) continue;
            ans += (ll)(i+j)*(k2-k1+1);
            ans %= mod;*/
        }
    }
    printf("%lld\n", ans);

    return 0;
}

 

D. 黑客-续

大原题说的就是它!!!NOIP多校联考9 数串

code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const ull base = 1e18;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct big
{
    ull a[60];
    big() {memset(a, 0, sizeof(a));}
    friend big operator + (const big &a, const big &b)
    {
        if(a.a[0] == 0) return b;
        if(b.a[0] == 0) return a;
        big c; c.a[0] = max(a.a[0], b.a[0]);
        for(register int i=1; i<=c.a[0]; i++)
        {
            c.a[i] += a.a[i] + b.a[i];
        }
        for(register int i=1; i<=c.a[0]; i++)
        {
            c.a[i+1] += c.a[i] / base;
            c.a[i] = c.a[i] % base;
        }
        if(c.a[c.a[0]+1]) c.a[0]++;
        return c;
    }
    big operator *= (int b)
    {
        for(register int i=1; i<=a[0]; i++) a[i] = a[i] * b;
        for(register int i=1; i<=a[0]; i++) 
        {
            a[i+1] += a[i] / base;
            a[i] %= base;
        }
        if(a[a[0]+1]) a[0]++;
        while(a[a[0]] == 0 && a[0] > 1) a[0]--;
        return *this;
    }
    big operator += (const big b)
    {
        a[0] = max(a[0], b.a[0]);
        for(register int i=1; i<=a[0]; i++)
        {
            a[i] = a[i] + b.a[i];
        }
        for(register int i=1; i<=a[0]; i++)
        {
            a[i+1] += a[i] / base;
            a[i] %= base;
        }
        if(a[a[0]+1]) a[0]++;
        return *this;
    }
    void print()
    {
        printf("%llu", a[a[0]]);
        if(a[0])
        {
            for(register int i=a[0]-1; i; i--)
            {
                printf("%018llu", a[i]);
            }
        }
        printf("\n");
    }
    void clear()
    {
        memset(a, 0, sizeof(a));
    }
};

int r[15], n, m, k, Max;
big ans1, ans2;
big cnt[2][1029], sum[2][1029], lj;

int main()
{
    freopen("hacker2.in", "r", stdin);
    freopen("hacker2.out", "w", stdout);
    
    n = read(); m = read(); k = read();
    for(register int i=1; i<=m; i++)
    {
        int a = read(), b = read();
        r[b] = r[b] | (1<<(a-1));
    }
    Max = (1 << k);
    for(register int i=1; i<=k; i++)
    {
        int zt = (1<<(i-1));
        cnt[1][zt].a[1] = 1; cnt[1][zt].a[0] = 1;
        sum[1][zt].a[1] = i; sum[1][zt].a[0] = 1;
    }
    for(register int pos=1; pos<n; pos++)
    {
        for(register int zt=0; zt<Max; zt++)
        {
            int now = pos & 1;
            if(cnt[now][zt].a[0])
            {
                sum[now][zt] *= 10;
                lj.clear();
                for(register int j=1; j<=k; j++)
                {
                    lj += cnt[now][zt];
                    if(!(r[j] & zt))
                    {
                        int nzt = zt | (1<<(j-1));
                        cnt[1-now][nzt] += cnt[now][zt];
                        sum[1-now][nzt] += sum[now][zt] + lj;
                    }
                }
                cnt[now][zt].clear();
                sum[now][zt].clear();
            }
        }
    }
    int an = n & 1;
    for(register int i=0; i<Max; i++)
    {
        ans1 += cnt[an][i]; 
        ans2 += sum[an][i]; 
    }
    ans1.print(); ans2.print();
    
    return 0;
}

 

posted @ 2022-09-12 14:55  Catherine_leah  阅读(29)  评论(0编辑  收藏  举报
/* */