Codeforces Round #813(Div.2) 题解

比赛链接

ABC 送分题,B的证明好像有点有趣,不过结论猜就完了
A

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9;

int n,k;
int a[105];

void solve(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	int p = k, cnt=0;
	for(int i=1;i<=k;i++){
		if(a[i] > p)++ cnt;
	}
	printf("%d\n",cnt);
}

signed main(){
	int te;scanf("%d",&te);
	while(te --)solve();

	return 0;
}


B

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9;

void solve(){
	int n;
	scanf("%d",&n);
	if(n%2==0){
		for(int i=1;i<=n;i+=2)printf("%d %d ",i+1,i);
		puts("");
	}else{
		printf("1 ");
		for(int i=2;i<=n;i+=2)printf("%d %d ",i+1,i);
		puts("");
	}
}

signed main(){
	int te;scanf("%d",&te);
	while(te--)solve();

	return 0;
}


C

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9;

int n;
int a[100005],lt[100005],vis[100005],mx[100005];

void solve(){
	memset(lt,0,sizeof lt);
	memset(vis,0,sizeof vis);
	memset(mx,0,sizeof mx);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	int lst=-1;
	for(int i=n;i>=2;i--){
		if(a[i] < a[i-1]){lst = i-1;break;}
	}
	for(int i=1;i<=n;i++)lt[a[i]] = i;
	for(int i=1;i<=n;i++)mx[i] = max(mx[i-1],lt[a[i]]);
	if(lst == -1){puts("0");return ;}
	for(int i=lst;i<=n;i++){
		if(lt[a[i]]!=i)continue;
		if(mx[i] == i){
			int cnt=0;
			for(int j=1;j<=i;j++){
				if(!vis[a[j]])++cnt,vis[a[j]]=1;
			}
			printf("%d\n",cnt);
			return ;
		}
	}
}

signed main(){
	int te;scanf("%d",&te);
	while(te --)solve();

	return 0;
}

D
首先注意到对于一个给定序列a1..an,答案就是

max(2mini=1nai,maxi=1n1min(ai,ai+1))

解释:首先我们要最大化的就是某两点最短路的最大值。考虑最小值ax的位置,如果x位于[l,r]之间,那么根据定义,lr之间连一条长为最小值的边,易知这一定是l和r的最短路长度,显然不是我们想要的,因为我们要的是最短路的最大值。如果x[l..r],我们考虑l和r的最短路长什么样,考虑两种情况:lpr 显然我们取能包含住x[p..l]&[p..r]就能取到最小值,即为2ax,显然这是这种情况最小值,第二种情况是直接lr,长度也很显然,是mina[l..r],最短距离即为二者最小值

现在我们想要最大化这个最小值,怎么做?显然第一种情况不可能再小了,只能第二种情况变大,注意到mina[l..r]mina[l+1..r],也就是说我们应该尽量缩小l r距离,显然当r=l+1可以。也就是得到了上式

如何利用好赋值?普通的贪心是会有反例的,但是我们发现,对于某一个答案来说,如果他能够通过k次赋值得到,那么比这个答案更小的一定也能不多于k次赋值得到,可以二分。

于是二分答案,判断修改次数是否小于k即可
(考场尝试了3次贪心都错了...)

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9,maxn=100005;

int n,k;
int a[maxn],b[maxn];

int check(int x){
	for(int i=1;i<=n;i++)b[i]=a[i];
	int tot=0;
	for(int i=1;i<=n;i++)
		if(a[i]*2 < x)++ tot, b[i] = 1e9;
	int res=2;
	for(int i=1;i<n;i++){
		res = min(res, (b[i]<x) + (b[i+1]<x));
	}
	return res+tot <= k;
}

void solve(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	int l=1,r=1e9,mid,ans;
	while(l <= r){
		mid = l+r>>1;
		if(check(mid))l = mid+1,ans=mid;
		else r = mid-1;
	}
	printf("%d\n",ans);
}

int main(){
	int te;scanf("%d",&te);
	while(te --)solve();
	return 0;
}

E1&E2
容斥一下,就转化为了求lcm(i,j,k)<i+j+k的方案
转化的目的是为了放缩
lcm(i,j,k)<i+j+k<3k,又因为是k的倍数,必然有lcm(i,j,k)=k 或者 lcm(i,j,k)=2ki+j>k(i+j>k是由2k<i+j+k得到)
先考虑第一种情况,显然ij都是k的约数,对于每个[l..r]我们可以暴力枚举k,统计在[l,k)k的约数个数,记为cnt,则其对答案的贡献即为(cnt2)

第二种情况?首先ij都是2k的约数,易知jk2,所以j只可能取2k3(如果为整数),将j代回不等式反解,k3<i<2k3i可取2k5k2,如果为整数,对于每个k额外判断一下即可
求出答案之后Crl+13即可
时间复杂度O(Tnlogn),可以过E1

对于T1e5,考虑离线,按照l从大到小排序
维护一个指针,从大到小扫描,对于某个位置cur,考虑cur2,cur3,...(相当于E1我是枚举因数,E2我是枚举倍数,对于每个因数只需要枚举一次)每次枚举到某个倍数mcur,第一次+0,第二次+1,...这样就相当于统计了E1中的(cnt2)(为什么第二次才+1?因为mcur相当于枚举的是k,而枚举到k的次数就相当于在[l..k)间k的因子个数cnt,第二次枚举到相当于有2个这种因数,C22=1,C32=3=1+2,...
查询的时候就相当于[1..r]的区间和,因为我l从大到小的,所以不存在不合法情况
树状数组维护即可

考虑对于[l..r]第二种情况的影响,对于2/5k,2/3k,k的形式,k必然为15的倍数,有约束kr2/5kl1k5(l1)2,对于km,k是15的倍数,k的个数为m/15,根据这个统计答案,对于1/2k,2/3k,k同理

E1

// by Balloons
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9,maxn=2e5+5;
vector<int>divsor[maxn];

void solve(){
	int l,r;scanf("%d%d",&l,&r);
	LL res=0;
	for(int i=l+2;i<=r;i++){
		int k = i,cnt=0;
		for(int tp=0;tp<divsor[k].size();tp++){
			int cur = divsor[k][tp];
			if(l<=cur && cur<k)++ cnt;
		}
		res += 1ll*cnt*(cnt-1)/2;
		if(k%15==0 && 2*k/5 >=l)++ res;
		if(k%6 == 0 && k/2 >=l) ++ res;
	}
	int len = r-l+1;
	LL ans = 1ll*len*(len-1)*(len-2) / 6;
	printf("%I64d\n",ans - res);
}

signed main(){
	for(int i=1;i<=200000;i++){
		for(int j=i;j<=200000;j+=i){
			divsor[j].push_back(i);
		}
	}
	int te;scanf("%d",&te);
	while(te--)solve();

	return 0;
}

E2

// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9,maxn=2e5+5;

struct node{int l,r,id;}a[maxn];
int cmp(node a,node b){return a.l > b.l;}
int buc[maxn],bit[maxn];
LL qu[maxn];

int lowbit(int x){return x&(-x);}
void add(int x,int tp){for(int i=x;i<=200000;i+=lowbit(i))bit[i] += tp;}
LL query(int x){LL res=0;for(int i=x;i;i-=lowbit(i))res += bit[i];return res;}

signed main(){
	int T;scanf("%d",&T);
	for(int i=1;i<=T;i++){
		scanf("%d%d",&a[i].l,&a[i].r);	
		a[i].id = i;
	}
	sort(a+1,a+T+1,cmp);
	
	int curid = 200001;
	for(int i=1;i<=T;i++){
		int lx = a[i].l, ly = a[i].r, lid = a[i].id;
		while(curid>lx){
			-- curid;
			for(int t=curid*2;t<=200000;t+=curid){
				add(t,buc[t]);
				++ buc[t];
			}
		}
		int len = ly-lx+1;
		LL ans = 1ll*len*(len-1)*(len-2)/6;
		ans -= query(ly);
		ans -= max(0, ly/15 - (lx-1) / 6);
		ans -= max(0ll, ly/6 - 1ll*(lx-1) / 3); 
		qu[lid] = ans;
	}
	for(int i=1;i<=T;i++)printf("%I64d\n",qu[i]);

	return 0;
}


posted @   SkyRainWind  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示