2019.10.26模拟赛

T1 序列

给定一长度为\(n\)的序列\(s\),定义其健美值为:\[\sum\limits_{i=1}^{n}|s_i - i|\]因为 zzq 喜欢健美,所以 zzq 希望减小\(s\)的健美值,以衬托 zzq 的健美。为了达到 zzq 的目的,zzq 希望你对序列进行旋转操作,一次旋转操作可以使序列中的所有元素前移一位,并使\(s_1\)移动到\(s_n\)。
可以进行任意次旋转操作,zzq 希望旋转后的健美值最小,请找出这个最小值。

SOV

智商检测题
我们发现对于每个数,移动每一次会使原本差小于0的数减少1的贡献,使原先差大于0的增加1的贡献。所以记录大于0的数以及小于0的数的个数,同时维护一个桶记录某一个差值有几个数,用于计算小于0变成大于0时的情况。枚举移动的距离,直接计算即可。

int main() {
    poread(n);
    for (register int i = 1; i <= n; ++i) poread(a[i]);
    for (register int i = 1; i <= n; ++i) {
        register int x = a[i] - i;
        x >= 0 ? (++cnt1, sum += x) : (++cnt2, sum += -x, ++b[-x]);
    }
    for (register int i = 1; i < n; ++i) {
        register int x = a[i] - 1, y = a[i] - n;
        --cnt1, sum -= x;
        ++cnt2, sum += -y, ++b[-y + i];
        sum += cnt1 - cnt2 + 1;
        if (b[i])
            cnt1 += b[i], cnt2 -= b[i];
        ans = min(ans, sum);
    }
    cout << ans << endl;
}

T3 动态数点

zzq 是一个善于思考的好学生。
于是 zzq 想往他的背包中放序列。
某一天 zzq 得到了一个长度为\(n\)的序列\(\{a_i\}\)。然后 zzq 说,如果对于一段区间\([L,R]\),存在\(L \leq k \leq R\)使得\(\forall i \in [L,R]\)都有\(a_k | a_i\),我们认为它有价值,价值为\(R - L\)(若不满足条件则没有价值)。
现在 zzq 想知道所有区间中价值最大为多少,最大价值的区间有多少个,以及这些区间分别是什么。

SOV

ST表维护区间gcd以及区间最小值,二分长度,如果该区间最小值等于区间gcd这个区间就是合法的。
复杂度\(O(n \log^2 n)\)

inline int gcd(int a,int b)
{
    while(b ^= a ^= b ^= a %= b);
    return a;
}
const int MAXN = 5e5 + 10;
int ST[MAXN][20];
int TS[MAXN][20];
int a[MAXN];
int n;
int ans[MAXN], tot;
inline int query(const int &l, const int &r)
{
    register int k = log2(r - l + 1);
    return gcd(ST[l][k], ST[r - (1 << k) + 1][k]);
}
inline int yreuq(const int &l, const int &r)
{
    register int k = log2(r - l + 1);
    return min(TS[l][k], TS[r - (1 << k) + 1][k]);
}
inline bool check(const int &mid)
{
    for(register int l = 1, r = l + mid - 1; r <= n; ++l,++r)
    {
        if(query(l, r) == yreuq(l, r))
            return true;
    }
    return false;
}
signed main()
{
    poread(n);
    for(register int i = 1; i <= n; ++i)
        poread(a[i]);
    for(register int i = 1; i <= n; ++i)
        ST[i][0] = a[i];
    int t = log2(n) + 1;
    for(register int j = 1; j <= t; ++j)
        for(register int i = 1; i<= n - (1 << j) + 1; ++i)
            ST[i][j] = gcd(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
    for(register int i = 1; i <= n; ++i)
        TS[i][0] = a[i];
    for(register int j = 1; j <= t; ++j)
        for(register int i = 1; i <= n - (1 << j) + 1; ++i)
            TS[i][j] = min(TS[i][j - 1], TS[i + (1 << (j - 1))][j - 1]);
    register int l = 2, r = n, mid, res;
    while(l <= r)
    {
        mid = (l + r) >> 1;
        if(check(mid))
            res = mid, l = mid + 1;
        else
            r = mid - 1;
    }
    for(register int i = 1, j = i + res - 1; j <= n; ++i, ++j)
        if(query(i, j) == yreuq(i, j))
            ans[++tot] = i;
    printf("%d %d\n",tot, res - 1);
    for(register int i = 1; i <= tot; ++i)
        printf("%d ", ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11745261.html

时间: 2024-08-04 05:33:03

2019.10.26模拟赛的相关文章

2019.10.24模拟赛赛后总结

本文原创,如果有不到位的地方欢迎通过右下角的按钮私信我! A.Icow Player 题目描述 被无止境的农活压榨得筋疲力尽后,Farmer John打算用他在MP3播放器市场新买的iCow来听些音乐,放松一下.FJ的iCow里存了N(1 <= N <= 1,000)首曲子,按1..N依次编号.至于曲子播放的顺序,则是按一个Farmer John自己设计的算法来决定: * 第i首曲子有一个初始权值R_i(1 <= R_i <= 10,000). * 当一首曲子播放完毕,接下来播放的

2019.9.26模拟赛

T1序列 这个题大佬们爆踩std了 给一个序列,其中一段排序后是某一等比数列子序列,求最长长度. 怎么做 数据太水导致枚举公比的过了 序列中每两个数做商,如果整除了的话,这个商一定是公比的次幂.我们从大到小枚举它是公比的几次幂,从而求到最小的公比.由于\(2^{60} > 1^{18}\),这个枚举只需要从59开始即可.时间复杂度\(O(64n)\) Code pow有精损注意判一下.(不要瞎搞手写分数次幂) #include <bits/stdc++.h> namespace fdat

2019.10.18模拟赛T3

题目大意: 求$\sum\limits_{i=1}^n\sum\limits_{j=1}^n[lcm(i,j)>n](n\leq 10^{10})$的值. 题解: 这题貌似有n多种做法... 为了更好统计,把原式变为$n^2-\sum\limits_{i=1}^n\sum\limits_{j=1}^n[lcm(i,j)\leq n]$. 然后开始毒瘤... 首先,考虑枚举$lcm(i,j)$,设为$d$,计算有多少对$i.j$的最小公倍数为$d$. 设$i=p_1^{a_1}p_2^{a_2}\

2019.10.22模拟赛

T1 合并集合 有\(n\)个集合,第\(i\)个集合记为\(S_i\),集合按环状排列,即第\(i + 1\)个集合右边是第\(i\)个集合,第\(n\)个集合右边是第\(i\)个集合. 一开始每个集合里只有一个数,每次你可以选择两个相邻的集合\(S,T\),然后合并成\(S \cup T\),之后你可以获得收益\(|S| \times |T|\),其中\(|S|\)表示集合\(S\)的元素个数. 你需要一直进行以上的操作直到只剩一个集合为止,求能获得的最大的收益之和. 断环为链,复制两倍区间

2019.10.24模拟赛

T1 古代龙人的谜题 Mark Douglas 是一名调查员.他接受了「调查古代龙人」的任务.经过千辛万苦,Mark 终于找到了一位古代龙人.Mark 找到他时,他正在摆弄一些秘药,其中一些药丸由于是从很久以前流传下来的,发出了独特的光泽.古代龙人告诉了 Mark 一些他想知道的事情,看了看手中的秘药,决定考一考这位来访者. 古代龙人手中共有\(n\)粒秘药,我们可以用\(1\)表示「古老的秘药」,其余的用\(0\)表示.他将它们排成一列.古代龙人认为平衡是美的,于是他问 Mark 能选出多少个

2019.10.31模拟赛

说在前面 考场遇见原题??? 上午刚做的 下午就\(T3\)考到了\(2333\) 然而还是因为忘了取模挂了28分 T1 Dove下跳棋 数据太水输出n-1可得90 Dove 喜爱下跳棋,在传统的跳棋基础之上,Dove 又延伸出了许多别的玩法.Dove 以一个一维数轴为棋盘下跳棋,总共会移动棋子?? ? 1 次.因为讨厌没有规律,所以Dove 每次只会恰好把棋子向右移动?? 个格子. Cicada 送给了Dove 一个长度为?? 的数列{??},为了表示感谢,Dove 打算以Cicada 送给他

10.2模拟赛总结

10.2 模拟赛总结 T1. 数位dp: 一个非常非常非常非常显然的数位 DP \([L,R] = [1,R]-[1,L-1]\) 所以是分别求两次小于等于某个数字的方案数 \(f(i,j,k)\) 表示从低位数起的第 \(i\) 位,按照规则计算后答案为 \(j\quad (j=0,1)\) \(k\) 表示只考虑后面结尾和 \(lmt\)后面几位 的大小关系 \((k=0,1)\) 考虑第 \(i+1\) 位,算一下新构成的数字并判断下大小就可以了 注意到 \(L,R\) 数据范围特别大,需

10.22 模拟赛

10.22 模拟赛 T1 染色 考虑每个连通块删成一棵树就好了. mmp场上就我路径压缩写炸.... #include<iostream> #define MAXN 200006 using namespace std; int n , m; int fa[MAXN] , siz[MAXN] , book[MAXN] , sz[MAXN]; int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int main() {

10.31 模拟赛

10.31 模拟赛 A LIS 考虑每个数字前从 $ m $ 降序构造到 $ a_i $ 即可. #include <iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<vector> using namespace std; #define MAXN 300006 int n , m , k; int A[MAXN]; vector<int&g