ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-07-23 08:35:43  阅读:114  来源: 互联网

标签:第四场 int return 联训 maxn 2022 ans solve include


甲国的军队

按照\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有