首页 > 其他分享 >Codeforces Round #823 (Div. 2)(持续更新)

Codeforces Round #823 (Div. 2)(持续更新)

时间:2022-09-26 23:13:30浏览次数:48  
标签:const int Codeforces RI pfx Div include Round define

Preface

本来没准备打这场比赛的,因为昨天出去high玩了一整天才发现今天才发现晚上有CF,遂报名rush一发

结果今天状态有点崩,先是B看错题导致浪费时间,然后又是D自己叉自己把原来对的思路扔了

最后一看E真NM可做,结果写了个复杂度错的代码(只能跑随机数据)直接凉凉,12:10分为了不影响室友睡觉直接开溜

但由于本身的Rating不高,因此没有掉分也是万幸


A. Planets

SB题,对于每个机场判断下用那种方法销毁飞机即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int t,n,c,a[N],num[N],ans;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d%d",&n,&c),i=1;i<=n;++i)
		scanf("%d",&a[i]),++num[a[i]];
		for (ans=0,i=1;i<=100;++i) ans+=min(num[i],c);
		for (i=1;i<=100;++i) num[i]=0;
		printf("%d\n",ans);
	}
	return 0;
}

B. Meeting on the Line

刚开始看错题以为总时间最短,以为是个SB题

后来发现怎么样例输出怎么有小数,遂仔细读题发现还是个SB题

一眼二分答案\(T\),检验的话考虑\(left=T-t_i\)就是每个人除去准备的时间剩下的最大走路时间

因此对第\(i\)个人来说,\(x_0\)可能的位置只能在\([x_i-left,x_i+left]\)中,把每个人的可能区间并起来看看是否为空集即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
const double EPS=1e-8;
struct itv
{
	double l,r;
}; int t,n,a[N],tim[N];
inline void merge(itv& A,const itv& B)
{
	A=(itv){max(A.l,B.l),min(A.r,B.r)};
}
inline bool check(const double& T)
{
	itv cur=(itv){-1e9,1e9}; for (RI i=1;i<=n;++i)
	{
		double left=T-tim[i]; if (left<0) return 0;
		merge(cur,(itv){1.0*a[i]-left,1.0*a[i]+left});
	}
	return cur.r-cur.l>-EPS;
}
inline double getans(const double& T)
{
	itv cur=(itv){-1e9,1e9}; for (RI i=1;i<=n;++i)
	{
		double left=T-tim[i]; if (left<0) return 0;
		merge(cur,(itv){1.0*a[i]-left,1.0*a[i]+left});
	}
	return cur.l;
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
		for (i=1;i<=n;++i) scanf("%d",&tim[i]);
		double L=0,R=2e8,mid,ans; while (R-L>EPS)
		if (check(mid=(L+R)/2.0)) ans=mid,R=mid; else L=mid;
		printf("%.8lf\n",getans(ans));
	}
	return 0;
}

C. Minimum Notation

有点技巧的贪心题

首先simple地考虑,肯定应该先把所有的0保留并放到最前面,这样的话我们需要把最后一个0前面出现的所有非零数全部删除

考虑最后处理这些被删除的数,显然把他们从小到大扔在最后面即可

那么在处理0时,若最后一个0后面还有其它字符怎么办呢,显然直接在其中重复找1的过程即可,当1找完后若还剩下就找2,以此类推

写个函数处理非常简便

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
char s[N]; int t,n,ct[10];
inline void solve(CI pos,const char& ch)
{
	if (pos>n||ch>'9') return; RI i; int lst=-1;
	for (i=pos;i<=n;++i) if (s[i]==ch) lst=i;
	if (!~lst) return solve(pos,ch+1);
	for (i=pos;i<=lst;++i) if (s[i]==ch) ++ct[ch-'0']; else ++ct[min(9,s[i]-'0'+1)];
	solve(lst+1,ch+1);
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; for (i=0;i<10;++i) ct[i]=0;
		scanf("%s",s+1); n=strlen(s+1); solve(1,'0');	
		for (j=0;j<10;++j) for (i=1;i<=ct[j];++i) putchar(j+'0'); putchar('\n');
	}
	return 0;
}

D. Prefixes and Suffixes

妈的本来都做出来了撒泡尿回来脑抽了把写了一半的代码删了,真想抽自己一个大耳光子

首先我们发现对于\(a_i\),它和\(b_{n-i+1}\)的相对位置还是一样的,即每次操作这两个数要么一起换要么一起不换

因此这两个数不能出现在同一个串中,但它们的顺序和位置是可以任意换的(手玩一下即可)

因此我们把每个\(a_i\)和\(b_{n-i+1}\)看作一个无序对\((x,y),x\le y\),统计每种无序对的个数

考虑构造一种合法方案,不难发现每个\((x,y),x\ne y\)的无序对的个数必须是偶数,然后类似回文地排布构造即可

若\(n\)为奇数,则\((x,y),x=y\)的个数等于\(1\)是合法的,否则不合法;若\(n\)为偶数,则\((x,y),x=y\)的个数只能为\(0\)

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,S=26;
int t,n,c[S][S]; char a[N],b[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; scanf("%d%s%s",&n,a+1,b+1); memset(c,0,sizeof(c));
		for (i=1;i<=n;++i)
		{
			int x=a[i]-'a',y=b[n-i+1]-'a'; if (x>y) swap(x,y); ++c[x][y];
		}
		bool flag=1; for (i=0;i<S;++i) for (j=i+1;j<S;++j)
		if (c[i][j]&1) flag=0; if (!flag) { puts("NO"); continue; }
		int sum=0; for (i=0;i<S;++i) sum+=c[i][i]%2;
		puts(sum>n%2?"NO":"YES");
	}
	return 0;
}

E. Maximums and Minimums

简单地提一下我比赛时的idea吧,今天有点晚了先懒得看官方sol了

首先这种区间最大最小值的经典套路无非两种,单调栈笛卡尔树,但笛卡尔树有一个显著的问题,在处理了其中一个后不好处理另一个(也许是我理解烂,若有方法实现务必请指教)

因此我们考虑单调栈,找出以每个\(a_i\)为最小值时的最大扩展区间,当时naive地以为区间长度总和是\(O(n)\)级别的,然后T了

其实仔细想想也是,如果放在笛卡尔树上这部分相当于所有子树的size和,显然如果树极不平衡(如退化成链)则总和是\(O(n^2)\)级别的

因此也说明了为什么我们在利用笛卡尔树处理问题时通常要加上启发式合并和DSU on tree的姿势了,不然复杂度是会爆炸的

说回正题,先不考虑复杂度,此时我们应该如何统计答案,由于还要考虑区间最大值,因此我们从\(a_i\)开始,向左右两边统计前缀最大值

考虑在\([L_i,i],[i,R_i]\)(\(L_i,R_i\)分别为\(a_i\)的最大扩展区间的左右端点)中各取一个前缀最大值,二者的最大值即为区间的最大值

现在先考虑在\([i,R_i]\)中枚举每一个前缀最大值\(pfx_j\),分情况讨论:

  • \(a_i|pfx_j\),此时在\([L_i,i]\)中合法的\(pfx_k\)为那些小于等于\(pfx_j\)的数量以及\(a_i|pfx_k\)且\(pfx_k>pfx_j\)的数量之和
  • \(a_i\nmid pfx_j\),此时在\([L_i,i]\)中合法的\(pfx_k\)为那些\(a_i|pfx_k\)且\(pfx_k>pfx_j\)的数量

显然可以开两个树状数组来维护\([L_i,i]\)中的信息,一个维护是\(a_i\)的倍数的一个维护不是\(a_i\)的倍数的

设区间总长度为\(S\),总复杂度为\(O(S\log a_i)\)(当数据随机时\(S=n\log n\)跑得飞快,随便过几十万的数据点)

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=500005;
int t,n,a[N],top,stk[N],L[N],R[N],lim,pfx; long long ans;
#define lowbit(x) (x&-x)
class Tree_Array1
{
	private:
		long long bit[N<<1];
	public:
		inline void add(int x,CI y)
		{
			for (;x<=lim;x+=lowbit(x)) bit[x]+=y;
		}
		inline int get(int x,int ret=0)
		{
			for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
		}
}T1;
class Tree_Array2
{
	private:
		long long bit[N<<1];
	public:
		inline void add(int x,CI y)
		{
			for (;x;x-=lowbit(x)) bit[x]+=y;
		}
		inline int get(int x,int ret=0)
		{
			for (;x<=lim;x+=lowbit(x)) ret+=bit[x]; return ret;
		}
}T2;
#undef lowbit
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; for (scanf("%d",&n),lim=ans=0,i=1;i<=n;++i)
		scanf("%d",&a[i]),lim=max(lim,a[i]);
		for (top=0,i=1;i<=n;++i)
		{
			while (top&&a[i]<a[stk[top]]) --top;
			if (!top) L[i]=1; else L[i]=stk[top]+1; stk[++top]=i;
		}
		for (top=0,i=n;i;--i)
		{
			while (top&&a[i]<=a[stk[top]]) --top;
			if (!top) R[i]=n; else R[i]=stk[top]-1; stk[++top]=i;
		}
		for (i=1;i<=n;++i)
		{
			for (pfx=0,j=i;j>=L[i];--j)
			if (pfx=max(pfx,a[j]),T1.add(pfx,1),pfx%a[i]==0) T2.add(pfx,1);
			for (pfx=0,j=i;j<=R[i];++j)
			if (pfx=max(pfx,a[j]),ans+=T2.get(pfx+1),pfx%a[i]==0) ans+=T1.get(pfx);
			for (pfx=0,j=i;j>=L[i];--j)
			if (pfx=max(pfx,a[j]),T1.add(pfx,-1),pfx%a[i]==0) T2.add(pfx,-1);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

标签:const,int,Codeforces,RI,pfx,Div,include,Round,define
From: https://www.cnblogs.com/cjjsb/p/16732893.html

相关文章

  • Codeforces Round #822 (Div. 2) - E. Rectangular Congruence
    同余Problem-E-Codeforces题意给一个长度为\(n(2<=n<350)\)的数组\(b_i\),\(0<=b_0,b_1...b_n<n\)要构造一个大小为\(n*n\)的矩阵A,\(a_{i,i}=b_i\),并且满......
  • Codeforces Round #822 (Div. 2)
    D.SlimeEscape被greedy整破防了。这是转换后的题面。考虑使用调整法构造,记2个序列分别为\(f,g\),那么一种调整法是,\(f\)加了没事就加了不管,否则我们再考虑往当......
  • Chrome插件开发background_js支持跨域请求与返回async和await的处理
    background.js的配置chrome.runtime.onMessage.addListener((request,sender,sendResponse)=>{switch(request.type){case'fetchChromeXmlrpc':......
  • Codeforces Round #822
    目录写在前面ABCDEF写在最后写在前面比赛地址:https://codeforces.com/contest/1734。复健后第一场div2,感觉有19年水平了。哈哈。A\(t\)组数据,每组数据给定一长......
  • Codeforces Round #822 (Div. 2)
    比赛链接CodeforcesRound#822(Div.2)D.SlimeEscape给一个长度为\(n\)的序列以及一个\(k\),表示当前位于\(k\)这个位置,要求该位置的数往左或者右,每次只能加上......
  • Codeforces Round #822 (Div. 2) D
    https://codeforces.com/contest/1734/problem/D题意有n只史莱姆,每只都有一个值,其中第k只被你控制,你希望能走到0或n+1这两个位置,也就是说遇到路上的史莱姆需要......
  • CodeForces 比赛记录
    带星号的表示vp。\(*\)CFRound601Div.1做出A和B1。B2.SendBoxestoAlice(HardVersion)考虑\(a\)的前缀和数列\(S\),在\(a\)中移动一个数,相当于在\(S......
  • Codeforces Round #822 D,E
    E.RectangularCongruence我们考虑对ar1,c1+ar2,c2≢ar1,c2+ar2,c1(modn)(同余情况下不同也是可以同时加任意数的可以感性理解一下)ar1,c1-ar1,c2≢ar2,c1......
  • CF Round 822 Div2 题解
    比赛链接A题SelectThreeSticks(签到)给定\(n\)根木棒,第\(i\)根木棒的长度为\(a_i\)。现在我们可以进行操作,每次操作选定一根木棒,将其长度增高或减少1。问至少需......
  • Codeforces Round #822 Div.2 整场题解
    目前还有E,F没有更新。A.SelectThreeSticks直接对\(a\)排序,选出来的木棍一定是相邻三项,都往中间靠更优。B.Bright,Nice,Brilliant最优方案就是每一行第一个......