首页 > 其他分享 >AGC 杂题

AGC 杂题

时间:2024-11-01 15:24:55浏览次数:5  
标签:Node 分界点 sta int top AGC mid 杂题

AGC029C Lexicographic constraints

有 \(n\) 个字符串,现在告知它们的长度 \(a_i\),求使得 \(\forall i\in[1,n),s_i<s_{i+1}\) 的最小字符集大小。

\(n\le 2\times 10^5,a_i\le 10^9\)

二分字符集大小 \(|\Sigma|\),分类讨论,设起始字符为 a

  • \(a_i<a_{i+1}\):显然 \(s_{i+1}\leftarrow s_i+(a_{i+1}-a_{i})\times \texttt{a}\) 是最优的;
  • \(a_i\ge a_{i+1}\):显然 \(s_{i+1}\) 为 \(s_i\) 长为 \(a_{i+1}\) 的前缀并将最末一位进一是最优的,注意若第一位产生了进位则这个 \(|\Sigma|\) 不合法。

由于 \(a_i\le 10^9\),所以我们并不能开字符串模拟。但是考虑到真正不是 a 的位置只有 \(O(n)\) 数量级,于是我们只要用栈维护这些位置即可。时间复杂度 \(O(n\log n)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
struct Node {
	int v, c;

	Node() {}
	Node(int v, int c):v(v), c(c) {}
};

int n;
int top;
int a[200010];
Node sta[200010];

inline void insert(int v, int x) {
	while(sta[top].v > v) --top;
	if(sta[top].v == v) sta[top].c++;
	else sta[++top] = Node(v, 1);
	if(top > 1 && sta[top].c == x) --top, insert(v - 1, x);
}

inline int chk(int x) {
	sta[top = 1] = Node(0, 0);
	for(int i = 2; i <= n; i++)
		if(a[i] <= a[i - 1]) insert(a[i], x);
	return sta[1].c == 0;
}

int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];

	int ct = 0;
	for(int i = 2; i <= n; i++) ct += a[i] > a[i - 1];
	if(ct == n - 1) return puts("1"), 0;
    
	int l = 2, r = n, res = 1;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(chk(mid)) res = mid, r = mid - 1;
		else l = mid + 1;
	} printf("%d\n", res);
	return 0;
}

AGC032E Modulo Pairing

给你 \(2n\) 个数,将数两两求和并模 \(m\),求得到的 \(n\) 个数中最大值的最小值。

\(n\le 10^5,a_i<m\le 10^9\)

先对 \(a\) 排序,对于每一对 \((i,j)\),把 \(i,j\) 用一条线连起来。

如果 \(a_i+a_j<M\),则用蓝色线,如果 \(a_i+a_j≥M\),则用红色线。

那么我们可以证明,一定存在一种最优情况,满足:

  • 存在一个分界点,使得它左右两侧没有匹配,也就是没有连线经过分界点。
  • 只考虑分界点左侧,则最小的数和最大的数连线,第二小的数和第二大的数连线,以此类推。
  • 分界点右侧也是一样,最小的和最大的连线。
  • 分界点左侧的线的颜色都是蓝色,分界点右侧的线的颜色都是红色。

用图表示就是这样:

怎么证明它是对的呢?可以使用调整法。

考虑两个数对,如果它们同色但不包含,或者它们异色但不相离,则可以调整成满足条件且不更劣的情况。如图:

二分分割点即可。时间复杂度 \(O(n\log n)\)。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+3;
int n,m,a[maxn];
bool check(int x){
    for(int i=x*2+1,j=2*n;i<j;i++,j--)
        if(a[i]+a[j]<m) return 0;
    return 1;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=2*n;i++) cin>>a[i];
    sort(a+1,a+2*n+1);
    int l=0,r=n,pos=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) r=mid-1,pos=mid*2;
        else l=mid+1;
    }
    int ans=0;
    for(int i=1,j=pos;i<j;i++,j--)
        ans=max(ans,a[i]+a[j]);
    for(int i=pos+1,j=2*n;i<j;i++,j--)
        ans=max(ans,(a[i]+a[j])-m);
    cout<<ans;
    return 0;
}

AGC032D Rotation Sort

给你一个排列 \(a\),可以执行以下操作任意次:

  • 选定一个区间 \([l,r]\),将 \(a_l\) 放到 \(a_r\) 之后,花费为 \(A\);
  • 选定一个区间 \([l,r]\),将 \(a_r\) 放到 \(a_l\) 之前,花费为 \(B\)。

求将排列变为升序的最小花费。

\(n\le 5000\)

显然最多每个数操作一次。分为三类:向前放,不动,向后放。其中不动的元素构成上升子序列。借此可以设计转移,设 \(f(i,j)\) 表示当前在 \(i\),最后一个不动的值为 \(j\),则有转移:

\[f(i,j)=\begin{cases} f(i-1,j)+A&a_i<j\\ \min_{k=1}^{j-1}f(i-1,k)& a_i=j\\ f(i-1,j)+B&a_i>j \end{cases}\]

记一个前缀 \(\min\),时间复杂度 \(O(n^2)\),可过。

但是你看这貌似可以上线段树?情况 1,3 相当于区间加。情况 2 相当于区间 \(\min\) + 单点修改,综上时间复杂度 \(O(n\log n)\)。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int maxn=5e3+3;
int n,A,B,a[maxn];
int tag[maxn<<2],mi[maxn<<2];
void pushup(int now){
    mi[now]=min(mi[ls],mi[rs]);
}
void pushdown(int now){
    if(tag[now]){
        mi[ls]+=tag[now];
        mi[rs]+=tag[now];
        tag[ls]+=tag[now];
        tag[rs]+=tag[now];
        tag[now]=0;
    }
}
void build(int now,int l,int r){
    if(l==r){
        if(l<a[1]) mi[now]=A;
        else if(l==a[1]) mi[now]=0;
        else mi[now]=B;
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid); build(rs,mid+1,r);
    pushup(now);
}
void modify(int now,int l,int r,int L,int R,int x){
    if(L<=l&&r<=R){
        mi[now]+=x;
        tag[now]+=x;
        return;
    }
    pushdown(now);
    int mid=(l+r)>>1;
    if(L<=mid) modify(ls,l,mid,L,R,x);
    if(mid+1<=R) modify(rs,mid+1,r,L,R,x);
    pushup(now);
}
void modify(int now,int l,int r,int pos,int x){
    if(l==r){
        mi[now]=x;
        return;
    }
    pushdown(now);
    int mid=(l+r)>>1;
    if(pos<=mid) modify(ls,l,mid,pos,x);
    else modify(rs,mid+1,r,pos,x);
    pushup(now);
}
int query(int now,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return mi[now];
    }
    pushdown(now);
    int mid=(l+r)>>1,res=0x3f3f3f3f3f3f3f3f;
    if(L<=mid) res=min(res,query(ls,l,mid,L,R));
    if(mid+1<=R) res=min(res,query(rs,mid+1,r,L,R));
    return res;
}
signed main(){
    cin>>n>>A>>B;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
    for(int i=2;i<=n;i++){
        if(a[i]>1) modify(1,1,n,a[i],query(1,1,n,1,a[i]-1));
        if(a[i]>1) modify(1,1,n,1,a[i]-1,A);
        if(a[i]<n) modify(1,1,n,a[i]+1,n,B);
    }
    int ans=0x3f3f3f3f3f3f3f3f;
    for(int i=1;i<=n;i++) ans=min(ans,query(1,1,n,i,i));
    cout<<ans;
    return 0;
}

标签:Node,分界点,sta,int,top,AGC,mid,杂题
From: https://www.cnblogs.com/DEV3937/p/18520317

相关文章

  • ABC 杂题
    ABC186EThrone有\(n\)个圆形排列的椅子,一开始你在\(s+1\)上,每次可以向右移动\(k\)个位置,求移动到\(1\)的最小步数,或报告无解。\(2\len,k\le10^9\)很容易想到构造方程:\[s+qk\equiv0\pmodn\]\[q\equiv(n-s)k^{-1}\pmodn\]直接exgcd求逆元,算出在\([1,n-1]\)......
  • 杂题选做1
    杂题选做1[ARC112F]DieSiedler注意到如果存在某一个\(j\)满足这种牌的数量大于等于\(2j\),那么一定会兑换为\(j\bmodn+1\)的牌。所以我们考虑这个过程的逆过程,就是将一张牌\(j\)换成\((j-1)!2^{j-1}\)张\(1\)号牌,最终全部的牌都被转化为了\(1\)号牌,但是结果并......
  • 数据结构杂题乱记
    由于是杂题乱记所以题目大多数不会太难。目录P2572[SCOI2010]序列操作题目内容思路代码P2572[SCOI2010]序列操作题目内容给你一个\(01\)序列,支持\(5\)种操作:0lr区间赋值为\(0\);1lr区间赋值为\(1\);2lr区间取反,即\(0\)变\(1\)、\(1\)变\(0\);3lr询......
  • 杂题随笔 10.31 两道LIS相关的题
    https://www.luogu.com.cn/problem/AT_abc354_f题意:给定一个序列a,求出所有的i使得任意一个a的最长子序列包含i。解法:我们先求这个序列的LIS的长度maxx,然后再去正着求一遍最长上升子序列和反着求一遍最长下降子序列即可,如果拼起来等于maxx那么说明i这个点是满足要求的点。注意细......
  • Day65 小贪心 & 自选杂题
    哎怎么必可公益赛被爆破了,怎么lifan还加了几道我们的训练题目作为补偿。CF不知道死了多久了,一上午都没有打成duel!今天上午精神状态明显好了很多,可能和咖啡有点关系吧。按照时间顺序写题吧。AT_arc070_b可以进行撤销背包,也可以算前后缀背包,都是记录方案数。不难的。AT_a......
  • 强连通分量学习笔记+杂题
    图论系列:前言:僕は明快さ故にアイロニー優柔不断なフォローミー後悔後悔夜の果て相关题单:戳我一.强连通分量相关定义基本摘自oiwiki,相关定义还是需要了解。(实际就是搬了个oiwiki)强连通分量主要在研究有向图可达性,针对的图类型为有向弱联通图。1.强连通定义强连通:对......
  • 杂题随笔 2024.10.25 两道图论
    最近在写abc375这场,最后的F和G是两道很典的图论题。https://atcoder.jp/contests/abc375/tasks/abc375_f题意:大致就是说给你一张图,有两种操作:第一种操作是把第i条边删掉,第二种操作是询问u,v两点的最短路。解法:这种题目印象里好像是考过几次了,把在线询问的顺序转变,倒着做,把减边......
  • 2024.10.23-25 杂题
    2024.10.23-25杂题P7323[WC2021]括号路径如果存在\((a,b,w)\),\((c,b,w)\)。那么\((a,c)\)就是一条合法路径。所以把\(a,c\)放入一个集合。然后合并新的的时候把\(w\)一样的合并了就行。最后统计每个"块"的数量,答案就是\(\sum_{i=1}^{n}C_{cnt_i}^{2}\)复杂度\(O(......
  • 吉米多维奇杂题选解——数列极限
    吉米多维奇杂题选解——数列极限一、用定义证明数列极限等式T1.求证:\(\lim\limits_{n\to\infty}\dfrac{n^\alpha}{c^n}=0,(a>0,c>1)\)证明:令\(k=\left\lfloor\alpha\right\rfloor+1\),则\(\dfrac{n^\alpha}{c^n}<\dfrac{n^k}{c^n}=\left(\dfrac{n}{(\sqrt[k]{c})^n}\......
  • 浅谈哈希及一类应用杂题
    浅谈哈希及一类应用杂题关于哈希的一些另类想法PS:与后文实际应用无关哈希的目的本质就是比较两个无法直接比较是否相同的一些东西,通过赋值来使其获得比较大小的能力,然后就想能不能搞一个随手就能整出来还不容易被卡常数比如之前好多题卡\(131\)什么的。如果我的数是纯随机的......