首页 > 其他分享 >CF351D - Jeff and Removing Periods 题解

CF351D - Jeff and Removing Periods 题解

时间:2024-02-28 15:15:53浏览次数:26  
标签:typedef ch int 题解 void Periods Removing inline define

首先做一点显然的转化:在进行第一次操作之后,可以将相同的数排在一起,这样一次就能删掉一种数。如果一开始就能删光一种数的话,那么次数就是区间颜色数,否则就是区间颜色数 \(+1\)。

所以现在原问题变成了两个问题:求区间内不同颜色数,判断区间内是否有某种颜色满足其出现位置构成等差数列。

第一问是经典问题,可以离线后 BIT 做到 \(O(n\log n)\)。

考虑第二问,设 \(pre_i\) 表示 \(a_i\) 上一次出现的位置,\(nxt_i\) 表示 \(a_i\) 下一次出现的位置。\(pos_i\) 表示最小的左端点 \(l\),使得 \([l,i]\) 中 \(a_i\) 出现的位置成等差数列,\(a_l\) 不一定等于 \(a_r\)。显然前两项易求,\(pos\) 可以递推求出。

那么原问题相当于是检验 \(\max_{i=l}^{r}[pos_i\le l][nxt_i>r]\) 是否为 \(1\)。考虑离线扫描线,用线段树维护所有 \(nxt_i>r\) 的位置的 \(pos_i\) 最小值。扫到 \(r\) 的时候直接把 \(pre_r\) 位置的值设为 \(+\infty\),再更新 \(r\) 位置的值,最后判断 \([l,r]\) 的最小值是否 \(\le l\) 即可。

时间复杂度 \(O(n\log n)\)。

卡常:不难发现 \(nxt\) 数组是没用的,而且由于值域小,算 \(pre\) 的时候可以直接开桶。

这样就可以拿到最优解了。

Code:

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define gt getchar
#define pt putchar
#define fst first
#define scd second
#define SZ(s) ((int)s.size())
#define all(s) s.begin(),s.end()
#define pb push_back
#define eb emplace_back
#define re register
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N=1e5+5;
const int inf=1e9;
const int SIZE=(1<<14);
using namespace std;
using namespace __gnu_pbds;
typedef pair<int,int> pii;
template<class T,class I> inline void chkmax(T &a,I b){a=max(a,(T)b);}
template<class T,class I> inline void chkmin(T &a,I b){a=min(a,(T)b);}
inline bool __(char ch){return ch>=48&&ch<=57;}
inline char gc(){
	static char buf[SIZE],*begin=buf,*end=buf;
	return begin==end&&(end=(begin=buf)+fread(buf,1,SIZE,stdin),begin==end)?EOF:*begin++;
}
template<class T> inline void read(T &x){
	x=0;bool sgn=0;static char ch=gc();
	while(!__(ch)&&ch!=EOF) sgn|=(ch=='-'),ch=gc();
	while(__(ch)) x=(x<<1)+(x<<3)+(ch&15),ch=gc();
	if(sgn) x=-x;
}
template<class T,class ...I> inline void read(T &x,I &...x1){
	read(x);
	read(x1...);
}
template<class T> inline void print(T x){
	static char stk[70];short top=0;
	if(x<0) pt('-');
	do{stk[++top]=x>=0?(x%10+48):(-(x%10)+48),x/=10;}while(x);
    while(top) pt(stk[top--]);
}
template<class T> inline void printsp(T x){
	print(x);
	putchar(' ');
}
template<class T> inline void println(T x){
	print(x);
	putchar('\n');
}
int n,m,a[N],pre[N],pos[N],ans[N],mp[N];
vector<pair<pii,int> > vec[N];
vector<pii> qry[N];
int c[N];
inline int lowbit(int x){
	return x&(-x);
}
inline void add(int x,int w){
	while(x<=n){
		c[x]+=w;
		x+=lowbit(x);
	} 
}
inline int query(int x){
	int ans=0;
	while(x){
		ans+=c[x];
		x-=lowbit(x); 
	}
	return ans;
}
struct Node{
	int l,r;
	int mn;
}node[N<<2];
inline int lson(int x){
	return x<<1;
}
inline int rson(int x){
	return x<<1|1;
}
inline void push_up(int p){
	node[p].mn=min(node[lson(p)].mn,node[rson(p)].mn);
}
void build(int p,int l,int r){
	node[p].l=l,node[p].r=r;
	node[p].mn=inf;
	if(l==r) return;
	int mid=l+((r-l)>>1);
	build(lson(p),l,mid);
	build(rson(p),mid+1,r);
}
void update(int p,int x,int w){
	int l=node[p].l,r=node[p].r;
	if(l==r) return node[p].mn=w,void();
	int mid=l+((r-l)>>1);
	if(x<=mid) update(lson(p),x,w);
	else update(rson(p),x,w);
	push_up(p);
}
int query(int p,int ql,int qr){
	int l=node[p].l,r=node[p].r;
	if(ql<=l&&r<=qr) return node[p].mn;
	int mid=l+((r-l)>>1),ans=inf;
	if(ql<=mid) chkmin(ans,query(lson(p),ql,qr));
	if(qr>mid) chkmin(ans,query(rson(p),ql,qr));
	return ans; 
}
signed main(){
	read(n);
	for(re int i=1;i<=n;++i){
		read(a[i]);
		pre[i]=mp[a[i]];
		mp[a[i]]=i;
	}
	for(re int i=1;i<=n;++i){
		if(!pre[i]) pos[i]=1;
		else if(i-pre[i]==pre[i]-pre[pre[i]]) pos[i]=pos[pre[i]];
		else pos[i]=pre[pre[i]]+1;
	}
	read(m);
	for(re int l,r,i=1;i<=m;++i){
		read(l,r);
		vec[l-1].eb(make_pair(pii(l,i),-1));
		vec[r].eb(make_pair(pii(l,i),1));
		qry[r].eb(l,i); 
	}
	for(re int r=1;r<=n;++r){
		add(pre[r]+1,1);
		for(auto qwq:vec[r]){
			int l=qwq.fst.fst,id=qwq.fst.scd,w=qwq.scd;
			ans[id]+=query(l)*w;
		}
	}
	build(1,1,n);
	for(re int r=1;r<=n;++r){
		update(1,r,pos[r]);
		if(pre[r]) update(1,pre[r],inf);
		for(auto qwq:qry[r]){
			int l=qwq.fst,id=qwq.scd; 
			ans[id]+=(query(1,l,r)>l);
		}
	}
	for(re int i=1;i<=m;++i) println(ans[i]);
	return 0;
}

标签:typedef,ch,int,题解,void,Periods,Removing,inline,define
From: https://www.cnblogs.com/syzqwq/p/18040452

相关文章

  • P9755 [CSP-S 2023] 种树 题解
    首先考虑如何求出第\(i\)棵树在\([l,r]\)时间段能长多高。这个东西可以差分一下然后等差数列求和。放一下代码:inlinelllcalc(inti,intx){ if(c[i]>=0){ return(lll)b[i]*x+(lll)c[i]*x*(x+1)/2; }else{ intd=(b[i]-1)/(-c[i]); if(x<=d)return(lll)b[i]*x+(l......
  • A-E题解
    A:对于任意一个满足条件的2*2矩阵,要么3个R和1个W,要么3个W和1个R。我们以3个R和1个W举例,只有以下4中情况满足:RR   RR   RW   WRRW  WR  RR   RR所以一种构造方法如下:奇数行全部放R;偶数行奇数列放R,偶数列放W即可。voidsolve(){intn;......
  • CF756D Bacterial Melee 题解
    给一个\(O(n^2)\)的做法。考虑从左到右扫描最终得到的字符串,如果当前的字符和前一个字符相同,就删掉这个字符。由题意可知,最终得到的字符串一定是\(s\)的一个子序列。我们定义状态\(dp[i][j]\)表示:当前子序列的最后一个字符是\(s[i]\),已经填完了最终字符串的前\(j\)个字......
  • CF1034E Little C Loves 3 III 题解
    这道题与P6097【模板】子集卷积基本相同,但是每个元素的值属于\([0,3]\),且\(n\le21\),时限\(\rm1s\)。在做P6097这道题的时候,我们多开了一维用来记录二进制下\(1\)的个数。但是这道题每个元素的值只属于\([0,3]\),我们可以用一种十分巧妙的方法:我们设\(f(x)\)表示\(......
  • P2065 [TJOI2011] 卡片 题解
    看大家建图时中间都连了质数点,发一个不用质数点的解法。我们可以先从源点向每一个蓝色卡片对应的点连一条边,再从每一个红色卡片对应的点向汇点连一条边。如果两张卡片可以一起拿走,那就在它们之间连一条边(蓝色连到红色),这些边的最大流量都是\(1\)。建好图以后我们就可以直接用Di......
  • CF111D Petya and Coloring 题解
    很明显这是一道组合题。首先特判一下,当\(m=1\)时,答案就是\(k^n\)。对于\(m>1\)的情况,我们可以得出一个结论:对于沿格子的线穿过的任何垂直线,会将棋盘分成两个非空的部分,这两个部分中的不同颜色的数量相同且总是不变。设这个不同颜色的数量为\(i\),那么左边这部分的颜色一定......
  • [USACO13MAR]Farm Painting S 题解
    看大家好多写的都用了四维偏序,给一个不用偏序的解法。简化一下题目,就是给你\(n\)个矩形,第\(i\)个矩形用\((x1_i,y1_i,x2_i,y2_i)\)表示,问你有多少个\(i\)满足:不存在另一个\(j\)使得\(x1_j\lex1_i\lex2_j\wedgey1_j\ley1_i\ley2_j\)。我们从左到右扫描每一个......
  • CF799D题解
    CF799D这里更容易进入且有翻译题意给定一个长宽为\(a\)和\(b\)的目标矩形、一个宽高为\(h\)和\(w\)的初始矩形及\(n\)个操作\(a_i\)。对于每个操作,可以将初始矩形的宽或高乘以\(a_i\),求使目标矩形能放入初始矩形的最少操作(目标矩形可以旋转90度)。解析这题算是......
  • [ABC303Ex] Constrained Tree Degree 题解
    AtCoder题面洛谷题面如果每个点的度数都知道了,那问题就转化成了P2290[HNOI2004]树的计数,直接求Prufer序列的个数即可,因为一个度数为\(d_i\)的点在Prufer序列中的出现次数是\(d_i-1\),所以答案是:\(\frac{(n-2)!}{\prod_{i=1}^{n}(d_i-1)!}\)。可以把\((n-2)!\)放到......
  • [COI2009] PLAHTE 题解
    首先对于每一个矩形,若\(x_2<0\),就将\(x_1,x_2\)均乘上\(-1\)再交换,对于\(y_1,y_2\)也做同样的操作。我们建立一个操作序列a[0~1000],和一个数组\(d\),每一个操作用\((x,y)\)表示,就是在\(d\)内把所有\(0\)到\(x\)的位置加上\(y\)。我们再定义一种新的操作\([x,y......