欢迎使用皮肤 Geek|

Tsawke

园龄:2年7个月粉丝:6关注:2

2023.02.16 模拟赛小结

2023.02.16 模拟赛小结

更好的阅读体验戳此进入

赛时思路

T1

给定 n×m01 矩阵,你需要构造一个初始矩阵,每过 1 单位时间,所有 1 会八向扩展使得周围所有 0 变成 1。过程不能使得 1 向矩阵外扩展,你需要使得你构造的初始矩阵能够最大化扩展次数,输出扩展次数与任一最优合法初始矩阵。

n×m106

一个显而易见的思路,用 3×3,5×5, 的矩阵去填充即可,并且尽量用更大的填充,二分答案然后枚举验证跑一下即可,实现上可以强行维护二位前缀和强行做,也可以写个宽搜之类的东西搞一搞,比较简单,签到题。

(最后拿到了 95pts 主要是因为 ty > M ? M : ty 最开始写成 n 了。。。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template < typename T = int >
inline T read(void);

int N, M;
vector < vector < bool > > mp;
vector < vector < int > > sum;
vector < vector < bool > > mark;
vector < vector < int > > csum;

bool Check(int siz){
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= M; ++j)
            mark[i][j] = false, csum[i][j] = 0;
    for(int i = siz + 1; i <= N - siz; ++i){
        for(int j = siz + 1; j <= M - siz; ++j){
            int sx = i - siz, sy = j - siz, tx = i + siz, ty = j + siz;
            int rsum = sum[tx][ty] - sum[sx - 1][ty] - sum[tx][sy - 1] + sum[sx - 1][sy - 1];
            int esum = ((siz << 1) | 1) * ((siz << 1) | 1);
            if(esum == rsum)mark[i][j] = true;
        }
    }
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= M; ++j)
            csum[i][j] = csum[i - 1][j] + csum[i][j - 1] - csum[i - 1][j - 1] + mark[i][j];
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= M; ++j){
            int sx = i - siz, sy = j - siz, tx = i + siz, ty = j + siz;
            if(mp[i][j] && !(csum[tx > N ? N : tx][ty > M ? M : ty] - csum[tx > N ? N : tx][sy - 1 < 0 ? 0 : sy - 1] - csum[sx - 1 < 0 ? 0 : sx - 1][ty > M ? M : ty] + csum[sx - 1 <= 0 ? 0 : sx - 1][sy - 1 < 0 ? 0 : sy - 1]))
                return false;
        }
    return true;
}

int main(){
    freopen("yawn.in", "r", stdin);
    freopen("yawn.out", "w", stdout);
    N = read(), M = read();
    for(int i = 0; i <= N; ++i){
        mark.emplace_back(vector < bool >());
        csum.emplace_back(vector < int >());
        for(int j = 0; j <= M; ++j)
            // mark[i] += false, csum[i] += 0;
            mark[i].emplace_back(false), csum[i].emplace_back(0);
    }
    // mp += vector < bool >();
    mp.emplace_back(vector < bool >());
    // vis += vector < bool >();
    for(int i = 0; i <= M; ++i)mp[0].emplace_back(false);//, vis[0] += false;
    for(int i = 1; i <= N; ++i){
        mp.emplace_back(vector < bool >());//   += vector < bool >();
        // vis += vector < bool >();
        // mp[i] += false;//, vis[i] += false;
        mp[i].emplace_back(false);
        for(int j = 1; j <= M; ++j){
            char c = getchar(); while(c != '.' && c != 'X')c = getchar();
            // mp[i] += c == '.' ? false : true;
            mp[i].emplace_back(c == '.' ? false : true);
            // vis[i] += c == '.' ? false : true;
        }
    }
    // sum += vector < int >();
    sum.emplace_back(vector < int >());
    for(int i = 0; i <= M; ++i)sum[0].emplace_back(0);  //sum[0] += 0;
    for(int i = 1; i <= N; ++i){
        // sum += vector < int >();
        sum.emplace_back(vector < int >());
        // sum[i] += 0;
        sum[i].emplace_back(0);
        for(int j = 1; j <= M; ++j)
            // sum[i] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mp[i][j];
            sum[i].emplace_back(sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mp[i][j]);
    }

    printf("Checking 50 %d\n\n\n\n\n", Check(50) ? 1 : 0);


    int l = 1, r = min((N - 1) >> 1, (M - 1) >> 1), ans = -1;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(Check(mid))ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    if(!~ans){
        printf("0\n");
        for(int i = 1; i <= N; ++i)
            for(int j = 1; j <= M; ++j)
                printf("%c%s", mp[i][j] ? 'X' : '.', j == M ? "\n" : "");
        exit(0);
    }
    int siz = ans;
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= M; ++j)
            mark[i][j] = false;
    for(int i = siz + 1; i <= N - siz; ++i){
        for(int j = siz + 1; j <= M - siz; ++j){
            int sx = i - siz, sy = j - siz, tx = i + siz, ty = j + siz;
            int rsum = sum[tx][ty] - sum[sx - 1][ty] - sum[tx][sy - 1] + sum[sx - 1][sy - 1];
            int esum = ((siz << 1) | 1) * ((siz << 1) | 1);
            if(esum == rsum)mark[i][j] = true;
        }
    }
    printf("%d\n", ans);
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= M; ++j)
            printf("%c%s", mark[i][j] ? 'X' : '.', j == M ? "\n" : "");
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

T2

给定序列,每次从序列中取数直至取空,每次取 ai 时的贡献为 min(ai1,ai+1),若不存在则贡献为 0,最大化贡献,求最大值。

赛时思路是考虑记录 vali 表示两侧数的较小值,记录 prii 表示 vali 减去其两侧 vali 的删除而导致的贡献减少量,以 pri 为关键字丢到优先队列里,然后每次取出后动态维护,即对 i 维护 prei,preprei,nxti,nxtnxtipri 变化,大概这样跑一下,当然最终对拍时发现假了。

1T10,1n106,1ai106

Code

/*
2
5
7 10 4 9 4
3
2 1 7

3
7
22 34 48 12 48 37 27
10
19 37 37 51 40 87 25 28 81 26
9
51 60 21 52 25 46 40 37 3
*/
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template < typename T = int >
inline T read(void);

int N;
int A[1100000];
int val[1100000];
int pri[1100000];
int pre[1100000], nxt[1100000];
bitset < 1100000 > vis;
ll ans(0);

priority_queue < pair < int, int >, vector < pair < int, int > >, less < pair < int, int > > > cur;

int main(){
    freopen("sum.in", "r", stdin);
    freopen("sum.out", "w", stdout);
    int T = read();
    while(T--){
        for(int i = 0; i <= N + 1; ++i)vis[i] = false;
        N = read();
        A[0] = A[N + 1] = 0; pre[0] = 0, nxt[N + 1] = N + 1, pre[N + 1] = N, nxt[0] = 1;
        val[0] = val[N + 1] = pri[0] = pri[N + 1] = 0, ans = 0;
        for(int i = 1; i <= N; ++i)A[i] = read();
        for(int i = 1; i <= N; ++i)pre[i] = i - 1, nxt[i] = i + 1;
        for(int i = 1; i <= N; ++i)val[i] = min(A[pre[i]], A[nxt[i]]);
        for(int i = 1; i <= N; ++i)pri[i] = val[i] - (val[pre[i]] - min(A[pre[pre[i]]], A[nxt[i]])) - (val[nxt[i]] - min(A[nxt[nxt[i]]], A[pre[i]]));
        for(int i = 1; i <= N; ++i)cur.push({pri[i], i});
        while(!cur.empty()){
            auto tp = cur.top(); cur.pop();
            int idx = tp.second;
            if(tp.first != pri[idx] || vis[idx])continue;
            ans += val[idx], vis[idx] = true;
            val[pre[idx]] = min(A[pre[pre[idx]]], A[nxt[idx]]);
            val[nxt[idx]] = min(A[nxt[nxt[idx]]], A[pre[idx]]);
            pri[pre[idx]] = val[pre[idx]] - (val[pre[pre[idx]]] - min(A[pre[pre[pre[idx]]]], A[nxt[idx]])) - (val[nxt[idx]] - min(A[nxt[nxt[idx]]], A[pre[pre[idx]]]));
            pri[nxt[idx]] = val[nxt[idx]] - (val[pre[idx]] - min(A[pre[pre[idx]]], A[nxt[nxt[idx]]])) - (val[nxt[nxt[idx]]] - min(A[nxt[nxt[nxt[idx]]]], A[pre[idx]]));
            cur.push({pri[pre[idx]], pre[idx]}), cur.push({pri[nxt[idx]], nxt[idx]});
            nxt[pre[idx]] = nxt[idx], pre[nxt[idx]] = pre[idx];
            int i = pre[pre[idx]];
            pri[i] = val[i] - (val[pre[i]] - min(A[pre[pre[i]]], A[nxt[i]])) - (val[nxt[i]] - min(A[nxt[nxt[i]]], A[pre[i]]));
            cur.push({pri[i], i});
            i = nxt[nxt[idx]];
            pri[i] = val[i] - (val[pre[i]] - min(A[pre[pre[i]]], A[nxt[i]])) - (val[nxt[i]] - min(A[nxt[nxt[i]]], A[pre[i]]));
            cur.push({pri[i], i});
        }printf("%lld\n", ans);
    }

    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    // int flag(1);
    char c = getchar();
    while(!isdigit(c))c = getchar();
    // if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    // ret *= flag;
    return ret;
}

T3

给定序列 pn,qn,形成函数序列 fn,其中 fi(x)=xpi+qi

给定 m 个操作,包括单点修改 pi,qi,以及给定 s,t,查询 ft(ft1(fs(x)))

n,m5×105

赛时写了个暴力,就不挂 Code 了。

T4

奇怪题,没写。

正解

T2

考虑三个数 x,y,z,若 xy,zy,那么删 y 最优,处理后最终剩下一个单峰的凸函数,考虑最大值次大值,显然其相邻且不会被作为答案,于是考虑第三大,若第三大与最大值相邻则删去最大值,反之则一定与次大值相邻,此时删除次大值,以此维护即可。

T3

首先说一下 @sssmzy 的高妙思路(确实巧妙,必须 %%%%%%%

考虑下取整的意义就是正常的除法之后再取整,于是直接考虑我们不考虑下取整,认为其为标准除法,然后则可以在线段树上合并,最后再取整即可。有一个问题就是这个东西并不是适用于所有,本题适用应该是因为对于 <1 的小数部分除以一个 1 的数一定不会变得 1,所以合并之后不会对答案造成影响。还有个细节就是不能用 long double,会 TLE,所以说 long double 真的很慢。(@sssmzy 就是因为 long doubleTLE

UPD

update-2023_02_16 初稿

本文作者:tsawke

本文链接:https://www.cnblogs.com/tsawke/p/17180234.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Tsawke  阅读(24)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起