NOIP多校联考12

问题 A: 【2022暑期集训8月13日】开根

讲解上说答案是pow(n, 1.0/m),我没试过,但caorong交了一个真的可以过哦,我用sqrt套sqrt解的m=4,剩下的单调函数二分答案嘛。(⊙o⊙)…本来想跳过的题居然成了唯一一个对的。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 0;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

ll n;
int m;
long double sq;

inline int read()
{
    int 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;
}

bool check(long double x)
{
    if(x*x*x - n < 1e-7) return 1;
    return 0;
}

bool check2(long double x)
{
    if(x*x*x*x*x - n < 1e-7) return 1;
    return 0;
}

int main()
{
    scanf("%lld", &n);
    m = read();
    if(m == 1)
    {
        printf("%lld\n", n);
        exit(0);
    }
    if(m == 2)
    {
        sq = sqrt(n);
        printf("%.3Lf\n", sq);
        exit(0);
    }
    if(m == 4)
    {
        sq = sqrt(n);
        sq = sqrt(sq);
        printf("%.3Lf\n", sq);
        exit(0);
    }
    if(m == 3)
    {
        long double l = 0, r = sqrt(n);
        while(r - l > 1e-7)
        {
            long double mid = (l + r)/2;
            if(check(mid)) l = mid;
            else r = mid;
        }
        printf("%.3Lf\n", l);
        exit(0);
    }
    if(m == 5)
    {
        long double l = 0, r = sqrt(n); r = sqrt(r);
        while(r - l > 1e-7)
        {
            long double mid = (l + r)/2;
            if(check2(mid)) l = mid;
            else r = mid;
        }
        printf("%.3Lf\n", l);
        exit(0);
    }

    return 0;
}
View Code

 

问题 B: 【2022暑期集训8月13日】迭代

把x套进去化简了半天,什么都没有化简出来,搞了一版把分子分母乘来乘去的东西到最后还TLE了个0分,暴搜都有12……事实上化简有一个好方法,把x写成a/b再带进去——

f(x) = (a^2+b^2)/2=a1/b1

a1+b1=(a+b)^2, a1-b1=(a-b)^2

an-1+bn-1=(a+b)^2^(n-1)

 

所以把上面的式子相加解a,相减解b,还要注意计算2^(n-1)的时候不能%mod,相关内容在《算法竞赛进阶指南》第148页,“面对乘方算式,把指数对模数的欧拉函数取模”,质数的欧拉函数-1就好了。

本来还打算每次求最大公约数分子分母化到最简,实践证明不需要……

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 3;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

int T;
ll n, x, ans, n2, a, b, wor, wtt, up, down, cat;

inline int read()
{
    int 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;
}

ll qpow(ll a, ll b, ll mod)
{
    ll ans = 1;
    //a = (a + mod) % mod;
    while(b)
    {
        if(b & 1ll) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1ll;
    }
    return ans;
}

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

int main()
{
    //freopen("iteration2.in", "r", stdin);
    
    T = read();
    n2 = qpow(2, mod-2, mod);
    while(T--)
    {
        scanf("%lld%lld", &x, &n);
        up = x; down = 1;
        cat = qpow(2, n-1, mod-1);
        //printf("cat = %lld\n", cat);
        wor = qpow(up+down, cat, mod);
        wtt = qpow(up-down, cat, mod);
        //printf("wor = %lld   wtt = %lld\n", wor, wtt);
        a = (wor+wtt)%mod*n2%mod; b = ((wor-wtt)*n2%mod+mod)%mod;
        /*printf("a = %lld b = %lld\n", a, b);
        ll ggk = gcd(a, b);
        while(ggk != 1)
        {
            a /= ggk; b /= ggk;
            ggk = gcd(a, b);
        }
        printf("a = %lld b = %lld\n", a, b);*/
        ans = a * qpow(b, mod-2, mod) % mod;
        printf("%lld\n", ans);
        //printf("333: %lld\n", 17*qpow(15, mod-2)%mod);
    }

    return 0;
}
View Code

 

问题 C: 【2022暑期集训8月13日】致富之路

除了单调栈什么都没想到,,,所以T掉了

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;
 
int m, n, q1[maxn], q2[maxn], t1, t2;
ll ans;
 
inline int read()
{
    int 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 Fac
{
    ll p, d;
    bool operator < (const Fac &T) const
    {
        return d > T.d;
    }
}fac[maxn];
 
struct Sop
{
    ll q, e;
    bool operator < (const Sop &T) const
    {
        return e < T.e;
    }
}sop[maxn];
 
int main()
{
    //freopen("monye2.in", "r", stdin);
     
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        fac[i].p = read(); fac[i].d = read();
    }
    for(int i=1; i<=n; i++)
    {
        sop[i].q = read(); sop[i].e = read();
    }
    sort(fac+1, fac+1+m);
    sort(sop+1, sop+1+n);
    for(int i=1; i<=m; i++)
    {
        while(t1 > 0 && fac[i].p <= fac[q1[t1]].p)
        {
            t1--;
        }
        q1[++t1] = i;
    }
    /*for(int i=1; i<=n; i++)
    {
        printf("%lld %lld\n", sop[i].q, sop[i].e);
    }*/
    for(int i=1; i<=n; i++)
    {
        while(t2 > 0 && sop[i].q >= sop[q2[t2]].q)
        {
            t2--;
        }
        q2[++t2] = i;
        //printf("q[%d] = %d\n", t2, q2[t2]);
    }
    //printf("t2 = %d t1 = %d\n", t2, t1);
    //printf("ccc : %d %d\n", q2[t2], q1[t1]);
    //printf("cmp %lld %lld\n", fac[q1[t1]].p, fac[q1[t1]].d);
    //printf("main : %lld %lld\n", sop[q2[t2]].q, sop[q2[t2]].e);
    for(int i=1; i<=t2; i++)
    {
        for(int j=1; j<=t1; j++)
        {
            if(sop[q2[i]].e <= fac[q1[j]].d) continue;
            if(sop[q2[i]].q <= fac[q1[j]].p) break;
            //printf("111\n");
            ans = max(ans, (sop[q2[i]].e-fac[q1[j]].d)*(sop[q2[i]].q-fac[q1[j]].p));
        }
    }
    printf("%lld\n", ans);
 
    return 0;
}
赛时60

发现还有一种不弹栈的写法——当然还是TLE60

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;
 
int m, n, q1[maxn], q2[maxn], t1, t2;
ll ans;
 
inline int read()
{
    int 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 Fac
{
    ll p, d;
    bool operator < (const Fac &T) const
    {
        return d < T.d;
    }
}fac[maxn];
 
struct Sop
{
    ll q, e;
    bool operator < (const Sop &T) const
    {
        return e > T.e;
    }
}sop[maxn];
 
int main()
{
    //freopen("monye2.in", "r", stdin);
     
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        fac[i].p = read(); fac[i].d = read();
    }
    for(int i=1; i<=n; i++)
    {
        sop[i].q = read(); sop[i].e = read();
    }
    sort(fac+1, fac+1+m);
    sort(sop+1, sop+1+n);
    for(int i=1; i<=m; i++)
    {
        if(fac[i].p >= fac[q1[t1]].p && t1!=0) continue;
        q1[++t1] = i;
    }
    /*for(int i=1; i<=n; i++)
    {
        printf("%lld %lld\n", sop[i].q, sop[i].e);
    }*/
    for(int i=1; i<=n; i++)
    {
        if(sop[i].q <= sop[q2[t2]].q && t2!=0) continue;
        q2[++t2] = i;
        //printf("q[%d] = %d\n", t2, q2[t2]);
    }
    //printf("t2 = %d t1 = %d\n", t2, t1);
    //printf("ccc : %d %d\n", q2[t2], q1[t1]);
    //printf("cmp %lld %lld\n", fac[q1[t1]].p, fac[q1[t1]].d);
    //printf("main : %lld %lld\n", sop[q2[t2]].q, sop[q2[t2]].e);
    for(int i=1; i<=t2; i++)
    {
        for(int j=1; j<=t1; j++)
        {
            if(sop[q2[i]].e <= fac[q1[j]].d) break;
            if(sop[q2[i]].q <= fac[q1[j]].p) continue;
            //printf("111\n");
            ans = max(ans, (sop[q2[i]].e-fac[q1[j]].d)*(sop[q2[i]].q-fac[q1[j]].p));
        }
    }
    printf("%lld\n", ans);
 
    return 0;
}
View Code

好几次听说随机化还挺好用的,终于见到了它的真面目,大开眼界%%%wenqizhi1125%%%

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

int m, n;

inline int read()
{
    int 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 Fac
{
    int p, d, x;
    bool operator < (const Fac &T) const
    {
        if(x != T.x) return x < T.x;
        else return p > T.p;
    }
}fac[maxn];

struct Sop
{
    int q, e, x;
    bool operator < (const Sop &T) const
    {
        if(x != T.x) return x > T.x;
        else return e < T.e;
    }
}sop[maxn];

int main()
{
    //freopen("monye2.in", "r", stdin);
    
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        fac[i].p = read(); fac[i].d = read();
        fac[i].x = fac[i].p + fac[i].d;
    }
    for(int i=1; i<=n; i++)
    {
        sop[i].q = read(); sop[i].e = read();
        sop[i].x = sop[i].q + sop[i].e;
    }
    sort(fac+1, fac+1+m);
    sort(sop+1, sop+1+n);
    int a = min(7000, n), b = min(5000, m);
    ll ans = 0;
    for(int i=1; i<=a; i++)
    {
        for(int j=1; j<=b; j++)
        {
            if(sop[i].e > fac[j].d && sop[i].q > fac[j].p)
            {
                ans = max(ans, 1ll*(sop[i].e-fac[j].d)*(sop[i].q-fac[j].p));
            }
        }
    }
    if(ans == 0) printf("45136189917\n");
    else printf("%lld\n", ans);

    return 0;
}
至于随机化,taAC了

 我很认真的二分了一下,WA 20……

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

int m, n, q1[maxn], q2[maxn], t1, t2;
ll mind = INF, minp = INF, ans;

inline int read()
{
    int 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 Fac
{
    ll p, d;
    bool operator < (const Fac &T) const 
    {
        return p < T.p;
    }
}fac[maxn];

struct Sop
{
    ll q, e;
    bool operator < (const Sop &T) const
    {
        return q < T.q;
    }
}sop[maxn];

void solve(int l, int r, int dl, int dr)
{
    if(l == r)
    {
        for(int i=dl; i<=dr; i++)
        {
            ans = max(ans, (sop[l].e-fac[i].d)*(sop[l].q-fac[i].p));
        }
        return;
    }
    if(dl == dr)
    {
        for(int i=l; i<=r; i++)
        {
            ans = max(ans, (sop[i].e-fac[dl].d)*(sop[i].q-fac[dl].p));
        }
        return;
    }
    int mid = (l + r) >> 1; ll res = 0;
    int dm = 0;
    for(int i=dl; i<=dr; i++)
    {
        if((sop[mid].e-fac[i].d)*(sop[mid].q-fac[mid].p) > res)
        {
            res = (sop[mid].e-fac[i].d)*(sop[mid].q-fac[mid].p);
            dm = i;
        }
    }
    solve(l, mid, dl, dm); solve(mid+1, r, dm, dr);
}

int main()
{
    //freopen("monye2.in", "r", stdin);
    
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        fac[i].p = read(); fac[i].d = read();
    }
    for(int i=1; i<=n; i++)
    {
        sop[i].q = read(); sop[i].e = read();
    }
    sort(fac+1, fac+1+m);
    sort(sop+1, sop+1+n);
    for(int i=1; i<=m; i++)
    {
        if(t1 == 0 || fac[i].d <= fac[q1[t1]].d) 
        {
            q1[++t1] = i; mind = min(mind, fac[i].d);
            minp = min(minp, fac[i].p);
        }
    }
    for(int i=1; i<=n; i++)
    {
        if(sop[i].e <= mind || sop[i].q <= minp) continue;//Del
        while(t2 > 0 && sop[i].e >= sop[q2[t2]].e)
        {
            t2--;
        }
        q2[++t2] = i;
    }
    solve(1, t2, 1, t1);
    printf("%lld\n", ans);

    return 0;
}
View Code

 看来没有太认真,我把直接的数组编号传进去了而不是栈的下标,如果传对的话,WA 70

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;
  
int m, n, q1[maxn], q2[maxn], t1, t2;
ll mind = INF, minp = INF, ans;
  
inline int read()
{
    int 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 Fac
{
    ll p, d;
    bool operator < (const Fac &T) const
    {
        return p < T.p;
    }
}fac[maxn];
  
struct Sop
{
    ll q, e;
    bool operator < (const Sop &T) const
    {
        return q < T.q;
    }
}sop[maxn];
  
void solve(int l, int r, int dl, int dr)
{
    if(l == r)
    {
        for(int i=dl; i<=dr; i++)
        {
            ans = max(ans, (sop[q2[l]].e-fac[q1[i]].d)*(sop[q2[l]].q-fac[q1[i]].p));
        }
        return;
    }
    if(dl == dr)
    {
        for(int i=l; i<=r; i++)
        {
            ans = max(ans, (sop[q2[i]].e-fac[q1[dl]].d)*(sop[q2[i]].q-fac[q1[dl]].p));
        }
        return;
    }
    int mid = (l + r) >> 1; ll res = 0;
    int dm = 0;
    for(int i=dl; i<=dr; i++)
    {
        if((sop[q2[mid]].e-fac[q1[i]].d)*(sop[q2[mid]].q-fac[q1[i]].p) > res)
        {
            res = (sop[q2[mid]].e-fac[q1[i]].d)*(sop[q2[mid]].q-fac[q1[i]].p);
            dm = i;
        }
    }
    solve(l, mid, dl, dm); solve(mid+1, r, dm, dr);
}
  
int main()
{
    //freopen("money.in", "r", stdin);
      
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        fac[i].p = read(); fac[i].d = read();
    }
    for(int i=1; i<=n; i++)
    {
        sop[i].q = read(); sop[i].e = read();
    }
    sort(fac+1, fac+1+m);
    sort(sop+1, sop+1+n);
    for(int i=1; i<=m; i++)
    {
        if(t1 == 0 || fac[i].d <= fac[q1[t1]].d) 
        {
            q1[++t1] = i; mind = min(mind, fac[i].d);
            minp = min(minp, fac[i].p);
        }
    }
    for(int i=1; i<=n; i++)
    {
        if(sop[i].e <= mind || sop[i].q <= minp) continue;//Del
        while(t2 > 0 && sop[i].e >= sop[q2[t2]].e)
        {
            t2--;
        }
        q2[++t2] = i;
    }
    solve(1, t2, 1, t1);
    printf("%lld\n", ans);
  
    return 0;
}
WA 70

 我严重怀疑accoders卡抄题解,我敢肯定我绝对没有抄错交上去就TLE 40,除非我交带有查重标号的明显的COPY代码……有人遇到过类似的问题吗?

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
const int maxn = 1e5 + 3;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const ll INF = 0x7ffffffffff;
 
int n, m, q1[maxn], q2[maxn], t1, t2;
ll ans;
 
inline int read()
{
    int 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 node 
{
    ll v, t;
    bool operator < (const node &T) const
    {
        return v < T.v;
    }
}fac[maxn], sop[maxn];
 
inline ll getans(int x, int y)
{
    if(sop[y].t < fac[x].t || sop[y].v < fac[x].v) return 0;
    return (sop[y].t-fac[x].t)*(sop[y].v-fac[x].v);
}
 
void solve(int l, int r, int dl, int dr)
{
    if(l > r || dl > dr) return;
    ll zwans;
    if(l == r)
    {
        for(int i=dl; i<=dr; i++)
        {
            zwans = getans(q1[l], q2[i]);
            ans = max(ans, zwans);
        }
        return;
    }
    if(dl == dr)
    {
        for(int i=l; i<=r; i++)
        {
            zwans = getans(q1[i], q2[dl]);
            ans = max(ans, zwans);
        }
        return;
    }
    int mid = (l + r) >> 1;
    ll nowans = 0; int id = 0;
    for(int i=dl; i<=dr; i++)
    {
        ll myans = getans(q1[mid], q2[i]);
        if(myans >= nowans) id=i, nowans=myans;
    }
    if(id == 0) return;
    ans = max(ans, nowans);
    solve(l, mid-1, dl, id);
    solve(mid+1, r, id, dr);
}
 
int main()
{
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        fac[i].v = read(); fac[i].t = read();
    }
    for(int i=1; i<=n; i++)
    {
        sop[i].v = read(); sop[i].t = read();
    }
    sort(fac+1, fac+1+m);
    sort(sop+1, sop+1+n);
    for(int i=1; i<=m; i++)
    {
        if(!t1) q1[++t1] = i;
        else
        {
            if(fac[i].t < fac[q1[t1]].t) q1[++t1] = i;
        }
    }
    for(int i=1; i<=n; i++)
    {
        while(t2 && sop[q2[t2]].t < sop[i].t) t2--;
        q2[++t2] = i;
    }
    //while(tal < t1 && fac[q1[tal]].t >= sop[q2[1]].t) tal++;
    while(t1 > 1 && fac[q1[t1]].v > sop[q2[t2]].v) t1--;
    solve(1, t1, 1, t2);
    printf("%lld\n", ans);
 
    return 0;
}
View Code

 我真的连变量名都没改,它再超时,好吧它又T了,真行真行真行……我就当我抄对了???无语啊

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
const int maxn = 1e5 + 3;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const ll INF = 0x7ffffffffff;
 
int n, m;
ll ans;
struct Goods 
{
    ll val, dat;
    bool operator < (const Goods &G) const 
    {
        return val < G.val;
    }
}buy[maxn], sell[maxn];
int st1[maxn], st2[maxn], tp1, tp2;
 
inline int read()
{
    int 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 ll getans(int x, int y)
{
    if(buy[y].dat < sell[x].dat && buy[y].val < sell[x].val) return 0;
    return (buy[y].dat - sell[x].dat)*(buy[y].val - sell[x].val);
}

inline void solve(int l, int r, int dl, int dr)
{
    if(l > r || dl > dr) return;
    ll zwans;
    if(l == r)
    {
        for(int i=dl; i<=dr; i++)
        {
            zwans = getans(st1[l], st2[i]);
            ans = max(ans, zwans);
        }
        return;
    }
    if(dl == dr)
    {
        for(int i=l; i<=r; i++)
        {
            zwans = getans(st1[i], st2[dl]);
            ans = max(ans, zwans);
        }
        return;
    }
    int mid = (l + r) >> 1;
    ll nowans = 0; int id = 0;
    for(int i=dl; i<=dr; i++)
    {
        ll myans = getans(st1[mid], st2[i]);
        if(myans >= nowans) id = i, nowans = myans;
    }
    ans = max(ans, nowans);
    solve(l, mid-1, dl, id);
    solve(mid+1, r, id, dr);
}

int main()
{
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        sell[i].val = read(); sell[i].dat = read();
    }
    for(int i=1; i<=n; i++)
    {
        buy[i].val = read(); buy[i].dat = read();
    }
    sort(sell+1, sell+1+m);
    sort(sell+1, sell+1+m);
    for(int i=1; i<=m; i++)
    {
        if(!tp1) st1[++tp1] = i;
        else 
        {
            if(sell[i].dat < sell[st1[tp1]].dat) st1[++tp1] = i;
        }
    }
    for(int i=1; i<=n; i++)
    {
        while(tp2 && buy[st2[tp2]].dat < buy[i].dat) --tp2;
        st2[++tp2] = i;
    }
    while(tp1 > 1 && sell[st1[tp1]].val > buy[st2[tp2]].val) --tp1;
    solve(1, tp1, 1, tp2);
    printf("%lld\n", ans);
 
    return 0;
}
问就是我也不知道它对不对

真的是够了啊,够了,下一页还有我就不粘了,除了CV的之外,每一版都是重写的(重抄的),如果我信任我的抄题解技术,那就一定是accoders再搞鬼……致富之路是我走不上了……

想看正解到caorong的博客园里去找吧,然后你就会发现我真的是什么都没改就T了啊,TLE10分也是过分了啊,就算抄的也是正解啊,说起来还是hz的题库良心……

 update:上面本来有张图的,但是它太丑了,所以我把它删掉了。

可能是因为过了一天,accoders的记性不太好了,也可能是因为换了一篇题解,也可能是因为昨天真的抄错了一晚上,总之就是Cat终于不带查重标号的A了!!!

至于为什么可以二分——把题解上的式子乘开就说明它是对的,不过新的问题是为什么Chen_jr的题解不用考虑负负得正的情况,难道是大佬自带的AC光环?感觉如果加个判断的话更严谨一点,虽然但是我抄的时候什么都没改。

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

int sta[maxn], stb[maxn], ta, tb, n, m;
ll ans;
  
inline int read()
{
    int 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 node 
{
    ll val, day;
    bool operator < (const node &T) const 
    {
        return day < T.day;
    }
}a[maxn], b[maxn], ls[maxn];//ls就是用来临时储存的,把栈里的再传回来

void solve(int l, int r, int dl, int dr)
{
    if(l > r || dl > dr) return;
    int mid = (dl + dr) >> 1;
    int pos = 0;
    ll mx = -0x3f3f3f3f;
    for(int i=l; i<=r; i++)
    {
        ll nans = (b[mid].day-a[i].day)*(b[mid].val-a[i].val);
        if(nans > mx)
        {
            mx = nans; pos = i;
        }
    }
    ans = max(ans, mx);
    solve(l, pos, dl, mid-1);
    solve(pos, r, mid+1, dr);
}

int main()
{
    //freopen("monye2.in", "r", stdin);
    
    m = read(); n = read();
    for(int i=1; i<=m; i++)
    {
        a[i].val = read(); a[i].day = read();
    }
    for(int i=1; i<=n; i++)
    {
        b[i].val = read(); b[i].day = read();
    }
    sort(a+1, a+1+m); sort(b+1, b+1+n);
    for(int i=m; i>=1; i--)
    {
        while(ta && a[sta[ta]].val >= a[i].val) ta--;//时间递减,val递增
        sta[++ta] = i;
    }
    for(int i=1; i<=ta; i++)
    {
        ls[i] = a[sta[ta-i+1]];//时间递增,val递减
    }
    for(int i=1; i<=ta; i++)
    {
        a[i] = ls[i];
    }
    for(int i=1; i<=n; i++)
    {
        while(tb && b[stb[tb]].val <= b[i].val) tb--;
        stb[++tb] = i;
    }
    for(int i=1; i<=tb; i++) ls[i] = b[stb[i]];
    for(int i=1; i<=tb; i++) b[i] = ls[i];
    int mi = 0x3f3f3f3f, pa = 1, pb = 0;
    for(int i=1; i<=tb; i++)
    {
        while(pa <= ta && a[pa].day < b[i].day) mi = min((ll)mi, a[pa++].val);
        if(mi < b[i].val) ls[++pb] = b[i];
    }
    tb = pb;
    for(int i=1; i<=tb; i++)
    {
        b[i] = ls[i];
    }
    solve(1, ta, 1, tb);
    printf("%lld\n", ans);
  
    return 0;
}
感谢Chen_jr

 

问题 D: 【2022暑期集训8月13日】平衡树

 把每一课子树的最大alpha存到线段树上,单点修改求最大值就是当前节点为根的最大alpha。

换根操作非常神奇,预处理出每个点为根时它最大的子树和次大的子树,(在根是1的这棵树上可能还是它的父节点,所以不能在这时dfs,否则就乱套了)。第一遍dfs的时候把根是1的情况全处理完了,所以最先得到的是1作为根的最大alpha值,dfs2的顺序是从上到下,进入新的一层递归时是以当前节点为根,所以在进入之前要做好预处理,返回之前(其实也是一种进入)也要把size变成即将出现的情况。

本来是只有最大的子树有用,但是再换根的过程中可能最大的子树成为根了就贡献不上了,这时就需要次大的子树发挥作用。判断子树有多少的方法1.maxsize==size[x]-1? 2.cnt>1?

query之后cnt要减1,去掉x和v之间的连边,如果x能成为换根后给v有贡献的子树,才用它的子树大小更新答案,预处理的是换根前新根的子树,查询之前的那一次查的是根自己(整棵树)。

感觉最难的部分是:当它有两个及以上的子节点的时候,他任意子树的大小满足alpha,我想到了用cnt记录子树大小然后不算自己,可是想不到合法的子树的子树大小怎么影响答案,解决方案就是把每一个点能产生的贡献(感觉说是负贡献更形象)全都存起来。

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

int n, k, size[maxn], si;
int mx[maxn], cmx[maxn], son[maxn];
long double ap[maxn];
  
inline int read()
{
    int 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 node 
{
    int next, to;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].next = head[x];
    head[x] = len;
}

struct tree 
{
    long double t[maxn<<2];
    void modify(int x, int l, int r, int pos, long double val)
    {
        if(l == r) 
        {
            t[x] = val; return;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) modify(x<<1, l, mid, pos, val);
        else modify(x<<1|1, mid+1, r, pos, val);
        t[x] = max(t[x<<1], t[x<<1|1]);
    }
    long double query()
    {
        return t[1];
    }
}t;

void dfs1(int x, int fa)
{
    size[x] = 1;
    int mx = 0;
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa) continue;
        dfs1(v, x);
        size[x] += size[v];
        mx = max(mx, size[v]);
    }
    //以1为根
    t.modify(1, 1, n, x, mx==size[x]-1?0:(long double)mx/size[x]);
}

void dfs2(int x, int fa)
{
    int cnt = 0;
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to; cnt++;//以x为根
        if(size[v] > mx[x])
        {
            cmx[x] = max(mx[x], cmx[x]);//次大的子树
            mx[x] = size[v];//最大的子树
            son[x] = v;
        }
        else cmx[x] = max(cmx[x], size[v]);
    }
    t.modify(1, 1, n, x, cnt>1?(long double)mx[x]/si:0);
    ap[x] = t.query(); cnt--;
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa) continue;
        size[x] = si - size[v];//以v为根
        t.modify(1, 1, n, x, cnt>1?(son[x]==v?(long double)cmx[x]/size[x]:(long double)mx[x]/size[x]):0);
        dfs2(v, x);
    }
    size[x] = si-size[fa];//即将返回,以fa为根,做好准备
    t.modify(1, 1, n, x, cnt>1?(son[x]==fa?(long double)cmx[x]/size[x]:(long double)mx[x]/size[x]):0);
}

int main()
{
    n = read(); k = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    dfs1(1, 0); si = size[1];
    dfs2(1, 0); sort(ap+1, ap+n+1);
    int m = read(), las = 0;
    for(int i=1; i<=m; i++)
    {
        int a = read()^(las*k), b = read()^(las*k);
        printf("%d\n", las=upper_bound(ap+1, ap+n+1, (long double)a/b)-ap-1);
    }
  
    return 0;
}
%%% Chen_jr

 

posted @ 2022-08-13 16:36  Catherine_leah  阅读(39)  评论(0编辑  收藏  举报
/* */