首页 > 其他分享 >20230223

20230223

时间:2023-02-23 17:23:06浏览次数:33  
标签:20230223 return pw int res ll ans

20230223

A

比较显然的,不考虑每天的需求,单看总量可以确定一个最小需求\(x_1\),再看单日最大需求量\(x_2\),可以证明两者的最大值一定可以满足条件,故最终答案为\(max(x_1,x_2)\)

code:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 4e5 + 5;
int n, q;
ll a[N], m, sum;
multiset<ll> s;
ll ans;
int main() {
    freopen("server.in", "r", stdin);
    freopen("server.out", "w", stdout);
    scanf("%d%lld%d", &n, &m, &q);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        s.insert(a[i]);
        sum += a[i];
    }
    ll mx = *s.rbegin();
    ans = max(mx, (sum - 1) / m + 1);
    printf("%lld\n", ans);
    int p;
    ll c;
    while (q--) {
        scanf("%d%lld", &p, &c);
        sum += c - a[p];
        s.erase(s.find(a[p]));
        s.insert(c);
        a[p] = c;
        ll mx = *s.rbegin();
        ans = max(mx, (sum - 1) / m + 1);
        printf("%lld\n", ans);
    }
}

B

\(40pts:\)

每次枚举\(l\),\(r\),直接反转,用哈希处理

\(30pts:\)

若\(c\)不在中间位置上,直接以\(c\)和\(mid\)作为\(l\),\(r\),不断向两端扩展

r若\(c\)在中间位置上,可以证明直接从两边向中间,和从中间向两边去找第一个不同的位置,在某一侧进行\(rev\),一定是最终答案(证明了半页)

\(100pts:\)

从特殊性质的结论出发,从两端向中间找第一个不同的位置,则两个位置必有一个是答案的端点,证明过程类比特殊性质

code:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5 + 5;
const int p = 1e9 + 7, bas = 233;
int n;
char s[N];
ll pw[N];
ll hl[N], hr[N];
ll calcl(int l, int r) { return ((hl[r] - hl[l - 1] * pw[r - l + 1] % p) % p + p) % p; }
ll calcr(int l, int r) { return ((hr[l] - hr[r + 1] * pw[r - l + 1] % p) % p + p) % p; }
bool rev_chk(int l, int r) {
    return ((((hl[n] - calcl(l, r) * pw[n - r] % p) % p + p) % p + calcr(l, r) * pw[n - r] % p) % p) ==
           ((((hr[1] - calcr(l, r) * pw[l - 1] % p) % p + p) % p + calcl(l, r) * pw[l - 1] % p) % p);
}
void solve1() {
    for (int i = 1; i <= n; i++)
        for (int j = i; j <= n; j++)
            if (rev_chk(i, j)) {
                printf("%d %d\n", i, j);
                return;
            }
    printf("-1 -1\n");
    return;
}
int vis[27];
int pos, wd;
void solve2() {
    memset(vis, 0, sizeof vis);
    for (int i = 1; i <= n; i++) ++vis[s[i] - 'a'];
    for (int i = 0; i < 26; i++)
        if (vis[i] == 1)
            wd = i;
    for (int i = 1; i <= n; i++)
        if (s[i] - 'a' == wd)
            pos = i;
    if (n % 2 == 0) {
        printf("-1 -1\n");
        return;
    }
    int mid = (n + 1) / 2;
    if (pos == mid) {
        int l = 1, r = n / 2;
        while (l <= n / 2 && s[l] == s[n - l + 1]) ++l;
        while (r >= 1 && s[r] == s[n - r + 1]) --r;
        if (l > r) {
            printf("1 1\n");
            return;
        }
        if (rev_chk(l, r))
            printf("%d %d\n", l, r);
        else
            printf("-1 -1\n");
    } else {
        int l = min(mid, pos), r = max(mid, pos);
        for (int i = 0; l - i >= 1 && r + i <= n; i++) {
            if (rev_chk(l - i, r + i)) {
                printf("%d %d\n", l - i, r + i);
                return;
            }
        }
        printf("-1 -1\n");
        return;
    }
}
void solve() { //solve1、solve2为赛时暴力,对应前40分与特殊性质
    scanf("%d %s", &n, s + 1);
    hr[n + 1] = 0;
    for (int i = 1; i <= n; i++) hl[i] = (hl[i - 1] * bas % p + s[i]) % p;
    for (int i = n; i; i--) hr[i] = (hr[i + 1] * bas % p + s[i]) % p;
    // if(n<=1000)
    // 	return solve1();
    // else
    // 	return solve2();
    int sl, sr;
    for (int i = 1; i <= (n + 2) / 2; i++)
        if (s[i] ^ s[n - i + 1]) {
            sl = i, sr = n - i + 1;
            break;
        }
    // printf("%d %d\n",sl,sr);
    for (int i = sl; i <= n; i++)
        if (rev_chk(sl, i)) {
            printf("%d %d\n", sl, i);
            return;
        }
    for (int i = sr; i; i--)
        if (rev_chk(i, sr)) {
            printf("%d %d\n", i, sr);
            return;
        }
    printf("-1 -1\n");
    return;
}
int main() {
    freopen("palindrome.in", "r", stdin);
    freopen("palindrome.out", "w", stdout);
    pw[0] = 1;
    for (int i = 1; i <= 100000; i++) pw[i] = pw[i - 1] * bas % p;
    int T;
    scanf("%d", &T);
    while (T--) solve();
    return 0;
}
/*
2
5
bacba
13
aabcdefebcdaa
*/

C

\(???pts:\)

将可以互相攻击到的点之间连一条边,可以观察出来得到的图是一张二分图,直接暴力建图跑二分图最大匹配,可以获得\(20-35pts\),实测匈牙利跑得会比网络流快一些

\(100pts:\)

直接贴题解(不会打太多\(\LaTeX\)

简单来说就是预处理出来所有小块的分法,然后把询问的大块拆开输出

code:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
int T;
int n, m;
int calc(int x, int y) { return (x - 1) * m + y; }
vector<int> e[1000005];
int dx[] = { 1, 1, 2, 2, -1, -1, -2, -2 };
int dy[] = { 2, -2, 1, -1, 2, -2, 1, -1 };
int col[N][N];
int match[1000005];
int vis[1000005];
bool dfs(int u, int tim) {
    if (vis[u] == tim)
        return false;
    vis[u] = tim;
    for (int v : e[u])
        if (!match[v] || dfs(match[v], tim)) {
            match[v] = u;
            return true;
        }
    return false;
}
struct node {
    int a, b, c, d;
};
vector<node> vec[9][9];
void pre() {
    int res = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            col[i][j] = ((i & 1) ^ (j & 1)) ? 1 : 0;
            int u = calc(i, j);
            vis[u] = 0;
            match[u] = 0;
            e[u].clear();
            if (!col[i][j])
                continue;
            for (int k = 0; k < 8; k++) {
                int x = i + dx[k], y = j + dy[k];
                if (x < 1 || x > n || y < 1 || y > m)
                    continue;
                int v = calc(x, y);
                e[u].push_back(v);
            }
        }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (col[i][j]) {
                int u = calc(i, j);
                if (dfs(u, u))
                    ++res;
            }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (!col[i][j]) {
                int v = calc(i, j);
                if (match[v]) {
                    int u = match[v];
                    int x = (u - 1) / m + 1, y = u - (x - 1) * m;
                    vec[n][m].push_back({ i, j, x, y });
                }
            }
}
void init() {
    for (int i = 1; i <= 8; i++)
        for (int j = 1; j <= 8; j++) n = i, m = j, pre();
}
// int n,m;
vector<node> ans;
int cal(int x, int y) { return x - y > 7 ? 4 : x - y + 1; }
void solve() {
    // int n,m;
    ans.clear();
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i += cal(n, i))
        for (int j = 1; j <= m; j += cal(m, j))
            for (auto x : vec[cal(n, i)][cal(m, j)])
                ans.push_back({ x.a + i - 1, x.b + j - 1, x.c + i - 1, x.d + j - 1 });
    printf("%d\n", ans.size());
    for (auto i : ans) printf("%d %d %d %d\n", i.a, i.b, i.c, i.d);
}
int main() {
    freopen("knight.in", "r", stdin);
    freopen("knight.out", "w", stdout);
    init();
    scanf("%d", &T);
    while (T--) solve();
    return 0;
}

D

\(20pts:\)

直接暴力枚举集合,判断是否为团

\(100pts:\)


然而赛时赛后都没几个人去写正解

随机化(随便艹)

每次shuffle一下点的顺序,然后依次判断每个点能否加入已有集合,去更新答案的最大值

优化思路1:如果当前点度数小于当前答案,那么选择它就一定不更优,故可以将其删除

优化思路2:如果当前剩下的点数已经不比答案多了,答案就不再会被更新了

加上卡时4s稳过,1s也不算困难

code:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
mt19937 rnd(time(0));
unordered_set<int> e[N];
int n, m, a[N];
int tmp[N], tot;
int ans, tim, res;
int main() {
    freopen("zhijiang.in", "r", stdin);
    freopen("zhijiang.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) a[i] = i;
    int x;
    for (int i = 1; i <= m; i++) {
        scanf("%d", &x);
        e[a[x]].insert(a[x + 1]);
        e[a[x + 1]].insert(a[x]);
        swap(a[x], a[x + 1]);
    }
    for (int i = 1; i <= n; i++)
        if (e[i].size())
            a[++tot] = i;
    while ((++tim %= 100) || (double)clock() / CLOCKS_PER_SEC < 0.95) {
        shuffle(a + 1, a + tot + 1, rnd);
        res = 0;
        for (int i = 1; i <= tot; i++)
            if (e[a[i]].size() >= res) {
                tmp[++res] = a[i];
                for (int j = 1; j < res; j++)
                    if (!e[a[i]].count(tmp[j])) {
                        --res;
                        break;
                    }
            }
        if (res > ans) {
            ans = res, m = 0;
            for (int i = 1; i <= tot; i++)
                if (e[a[i]].size() >= res)
                    a[++m] = a[i];
            tot = m;
        }
    }
    printf("%d\n", ans);
    return 0;
}

标签:20230223,return,pw,int,res,ll,ans
From: https://www.cnblogs.com/overthesky/p/17148827.html

相关文章