其他分享
首页 > 其他分享> > 2022 年多校冲刺 NOIP 联训测试 第四场

2022 年多校冲刺 NOIP 联训测试 第四场

作者:互联网

甲国的军队

按照\(b[i] - a[i]\)排序即可,考场想法是\(b[i] - a[i]\)代表的是可以重复利用的,显然选大的

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int x = 0; char c; c = getchar();
    while(c < '0' || c > '9')c = getchar();
    while(c <= '9' && c >= '0')x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
const int maxn = 100005;
typedef long long ll;
int n;
struct node{int a, b;}d[maxn];
bool cmp(node x , node y){return x.b - x.a > y.b - y.a;}
void work(){
    n = read();
    for(int i = 1; i <= n; ++i)d[i].a = read(), d[i].b = read();
    sort(d + 1, d + n + 1, cmp);
    ll now = 0, ans = 0;
    for(int i = 1; i <= n; ++i){
        if(now < d[i].b)ans += d[i].b - now, now = d[i].b;
        now -= d[i].a;
    }
    printf("%lld\n",ans);
}
int main(){
    int T = read();
    for(int i = 1; i <= T; ++i)work();
    return 0;
}

虚弱

二分\(x\),为啥要三分呢?直接把绝对值拆了不就行了?

注意\(eps\)的选取

code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 200005;
const double eps = 0.000000000005;
const double inf = 0x3f3f3f3f3f3f;
int n;
double a[maxn], ans = inf, ls[maxn];
int check(double mid){
    for(int i = 1; i <= n; ++i)ls[i] = a[i] + mid;
    double mi = ls[1], mx = ls[1];
    double sx = 0, sy = 0;
    for(int i = 1; i <= n; ++i){
        sx += ls[i], sy += ls[i];
        mi = min(mi, sx), mx = max(mx, sy);
        if(sx > 0)sx = 0;
        if(sy < 0)sy = 0;
    }
    double ab = max(abs(mx), abs(mi));
    if(ab < ans)ans = ab;
    if(mx < 0)return false;
    if(mi > 0)return true;
    if(abs(mx) > abs(mi))return true;
    return false;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)scanf("%lf",&a[i]);
    double l = -10000, r = 10000;
    while(r - l >= eps){
        double mid = (l + r) / 2;
        if(check(mid))r = mid;
        else l = mid;
    }
    printf("%.6lf",ans);
    return 0;
}

萨鲁曼的半兽人

不难发现其实是求最少将序列划分成几段,使得每一段都为回文,划分的段可以有交叉

考场就留了半小时打这题,结果可想而知

回文自动机的板子都忘了,我真是废物。

求回文可以\(hash\) + 二分,但是回文自动机显然更方便(而且回文长度在右端点)

用线段树维护\(DP\)数组,\(DP\)就很显然了,只需要在最长的回文范围内查询最小值 + 1更新当前位置答案

code
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn = 100005;
char c[maxn];
int n, fail[maxn], las, len[maxn], now = 1, ch[maxn][27], rl[maxn];

struct tree{
    int t[maxn << 2 | 1];
    void modify(int x, int l, int r, int pos, int val){
        if(l == r)return t[x] = val, void();
        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] = min(t[x << 1], t[x << 1 | 1]);
    }

    int query(int x, int l, int r, int L, int R){
        if(L <= l && r <= R)return t[x];
        int mid = (l + r) >> 1;
        int ans = maxn;
        if(L <= mid)ans = query(x << 1, l, mid, L, R);
        if(R > mid) ans = min(ans, query(x << 1 | 1, mid + 1, r, L, R));
        return ans;
    }
}T;
void work(){
    c[0] = '#';
    // T.clear();
    memset(ch, 0 ,sizeof(ch));
    memset(fail, 0 ,sizeof(fail));
    las = 0;now = 1;
    len[1] = -1; fail[0] = 1;
    for(int i = 1; i <= n; ++i){
        while(c[i - len[las] - 1] != c[i])las = fail[las];
        if(!ch[las][c[i] - 'a']){
            len[++now] = len[las] + 2;
            int j = fail[las];
            while(c[i - len[j] - 1] != c[i])j = fail[j];
            fail[now] = ch[j][c[i] - 'a'];
            ch[las][c[i] - 'a'] = now;
        }
        las = ch[las][c[i] - 'a'];
        rl[i] = len[las];
    }
    T.modify(1, 0, n, 0, -1);
    for(int i = 1; i <= n; ++i)T.modify(1, 0, n, i, T.query(1, 0, n, i - rl[i], i - 1) + 1);
    printf("%d\n",T.query(1, 0, n, n, n));
}
int main(){
    // freopen("c2.in","r",stdin);
    while(~scanf("%s",c + 1)){
        n = strlen(c + 1);
        work();
    }
    return 0;
}

序列

痛失\(70\)分!!

考场想到正解,每次处理一个区间\(solve(l, r)\)

先在与\(l\)奇偶性相同的位置找最小值,再在最小值后面奇偶性不同的位置找最小值,构成一个二元组

设两个最小值位置为\(x, y\)

接下来递归处理\(solve(l , x - 1)\) \(solve(x + 1, y - 1)\) \(solve(y + 1, r)\)

需要注意的是\(solve(x + 1, y - 1)\)必须在\(solve(l, r)\)之后,而两边的区间不必

也就是说对于部分的二元组,他们之间有严格的先后顺序,而另一部分没有

我的做法是建图拓扑

但是考场为了省事用了反向建边+反向统计答案

然而事实证明负负不得正.....

code
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
inline int read(){
    int x = 0; char c; c = getchar();
    while(c < '0' || c > '9')c = getchar();
    while(c <= '9' && c >= '0')x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
const int maxn = 2e5 + 55;
int q[maxn], n, mp[maxn], ls[maxn], hn, ans[maxn], pnow = 0;
struct tree{
    int t[maxn << 1 | 1];
    void built(int x ,int l, int r){
        if(l == r){t[x] = ls[l]; return;}
        int mid = (l + r) >> 1;
        built(x << 1, l, mid);
        built(x << 1 | 1, mid + 1, r);
        t[x] = min(t[x << 1], t[x << 1 | 1]);
    }
    int query(int x, int l, int r, int L, int R){
        if(L <= l && r <= R)return t[x];
        int mid = (l + r) >> 1, ans = maxn;
        if(L <= mid)ans = query(x << 1, l, mid, L, R);
        if(R > mid)ans = min(ans, query(x << 1 | 1, mid + 1, r, L, R));
        return ans;
    }
}T1,T2;
struct node{
    int x, y;
    node(){}
    node(int x_,int y_){x = x_; y = y_;}
    friend bool operator < (const node a, const node b){return a.x > b.x;}
};
priority_queue<node>Q;
int head[maxn], tot, rd[maxn], rm[maxn];
struct edge{int to,net;}e[maxn];
void add(int u, int v){
    e[++tot].net = head[u];
    head[u] = tot;
    e[tot].to = v;
    ++rd[v];
}
void solve(int l, int r, int u){
    if(l >= r)return;
    if(l + 1 == r){
        rm[q[l]] = q[r];
        if(u) add(u, q[l]);
        return;
    }
    int m1, m2;
    if(l & 1) m1 = T1.query(1, 1, hn, (l + 1) >> 1, r >> 1);
    else m1 = T2.query(1, 1, hn, (l + 1) >> 1, r >> 1);
    int p1 = mp[m1];
    if(l & 1) m2 = T2.query(1, 1, hn, (p1 + 2) >> 1, (r + 1) >> 1);
    else m2 = T1.query(1, 1, hn, (p1 + 2) >> 1, (r + 1) >> 1);
    int p2 = mp[m2];
    rm[m1] = m2;
    if(u) add(u, m1);
    solve(l, p1 - 1, u);
    solve(p2 + 1, r, u);
    solve(p1 + 1, p2 - 1, m1);
}
int main(){
    n = read();  hn = n / 2;
    for(int i = 1; i <= n; ++i)q[i] = read();
    for(int i = 1; i <= n; ++i)mp[q[i]] = i;
    for(int i = 1; i <= hn; ++i)ls[i] = q[i + i - 1];  T1.built(1, 1, hn);
    for(int i = 1; i <= hn; ++i)ls[i] = q[i + i];      T2.built(1, 1, hn);
    solve(1, n, 0);
    for(int i = 1; i <= n; ++i)if(rd[i] == 0 && rm[i])Q.push(node(i, rm[i]));
    while(!Q.empty()){
        node now = Q.top(); Q.pop();
        ans[++pnow] = now.x;  ans[++pnow] = now.y;
        for(int i = head[now.x]; i; i = e[i].net){
            int v = e[i].to;  --rd[v];
            if(rd[v] == 0)Q.push(node(v, rm[v]));
        }
    }
    for(int i = 1; i <= n; ++i)printf("%d ",ans[i]);
    return 0;
}

标签:第四场,int,return,联训,maxn,2022,ans,solve,include
来源: https://www.cnblogs.com/Chencgy/p/16508741.html