首页 > 其他分享 >Codeforces Round 970 (Div. 3) 复盘

Codeforces Round 970 (Div. 3) 复盘

时间:2024-09-15 20:50:50浏览次数:8  
标签:字符 970 int Codeforces times 偶数 leq 字符串 Div

Codeforces Round 970 (Div. 3)

Sep/01/2024 22:35UTC+8 length 02:15

好闲啊,还要写 div3 的复盘,就当听歌的同时练习翻译兼打字了。总而言之还是太菜了

# Who = Penalty * A B C D E F G H
1624 BaSEc1d 6 250 +00:04 +00:19 +00:24 +00:34 +01:17 +01:32

因为开学前几天怕打扰室友睡觉影响人际关系,做完 D 题之后就敲键盘不敢太快了,然后理论上想做完 E 之后就睡,但是发现 F 是水题。

G. Sakurako's Task

给你一个长为 \(n\) 的序列 \(a\),可以选择两个数 \(i,j(i\neq j)\),满足 \(a_i\geq a_j\),然后进行赋值 \(a_i=a_i-a_j\) 或 \(a_i=a_i+a_j\)。可以进行上述操作无数次,要求最大化 \(mex_k\)。其中 \(mex_k\) 是指序列中第 \(k\) 大没有出现的自然数(自然数包括 \(0\))。例如 \(mex_2(\{0,2,4\})=3\)。

\(1\leq n\leq 2\times 10^5,1\leq k\leq 10^9\)

显然无论 \(mex_k\) 中 \(k\) 取多少,我们都要尽量让 \(a\) 中元素尽可能小且不重复。

发现如果 \(a\) 中有 \(1\),那么可以将 \(a\) 轻松变成 \({0,1,2,3,4,\dots}\)

我们现在需要判断能不能构造出一个 \(1\) 出来,可以大胆猜测如果 \(a\) 中所有元素的 \(\rm gcd\) 为 \(1\),就能构造出 \(1\) 来。

额我不想证了,因为让我证我估计短时间也证不出来。根据拓展欧几里得,\(ax+by=\gcd(a,b)\) 的解有无数个,似乎就能说明问题。

如果 \(\gcd\) 是其他大于 \(1\) 的数 \(x\),那么则我们只能构造出 \(0,x,2x,3x,\dots\) 来,容易发现这也是这种情况下最优秀的

然后代码就比较好写了

scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
sort(a+1,a+1+n);int minv=__gcd(a[1],a[2]);
if(n==1)goto ptans;
for(int i=3;i<=n;++i)minv=__gcd(minv,a[i]);
a[1]=0;
for(int i=2;i<=n;++i)a[i]=(i-1)*minv;
ptans:
for(int i=1;i<=n;++i){
    if(a[i]-(i-1)>=k){
        printf("%d\n",k+i-1-1);
        goto end;
    }
}printf("%d\n",k+n-1);
end:;

H. Sakurako's Test

给一个长为 \(n\) 的数组,给出一个数 \(x\),可以进行任意次下列操作

  • 选择一个数 \(i(1\leq i\leq n)\),满足 \(a_i\geq x\)。进行赋值 \(a_i=a_i-x\)。

现在想要通过这一操作最小化 \(a\) 数组的中位数。对于每个数组,给 \(q\) 次询问,每次给出一个 \(x\),求出能最小化的中位数的值。(注意如果 \(n\) 是偶数,这里中位数指的是第 \(\frac{n+2}{2}\) 大的数)

\(1\leq \sum n,\sum q\leq 10^5,1\leq a_i\leq n,1\leq x\leq n\)

显然对于每个数,让它尽可能小是最优的,即 \(a_i\to a_i \bmod x\)。

那么我们现在要求转换后的数组的中位数,容易发现 \(x\) 的值很多,显然不能每次都暴力转化。

观察题目数据范围,\(1\leq a_i\leq n\),可以考虑将 \(a_i\) 存在桶 \(b_{a_i}\) 内,顺便求一下这个桶的前缀和 \(s\)。

因为取模后每个数 \(a_i\in[0,x-1]\),如果在 \([0,x-1]\) 内二分答案,每次求取模后小于等于 \(y\) 的数的个数,则可以在 \(n/x\) 的时间内求出答案(求法就是从头到尾枚举桶每个长度为 \(x\) 的区域(区域首尾相连),该区域内的答案即为该区域前 \(y\) 个桶的总和)。(懒得写数学公式了)

因为我们知道 $\sum_{x=1}^{n} n/x=n\sum_{x=1}^{n} 1/x\approx n\ln n $。所以总的复杂度 \(O(n\log^2n)\)

int n,q,ans[N],a[N],s[N],m,ques[N];
bool check(int lim,int k){
	int cnt=0;
	for(int i=0;i<=n;i+=k)
		cnt+=s[min(i+lim,n)]-(i==0?0:s[i-1]);
	return cnt>=n/2+1;
}
inline int solve(int k){
	int l=0,r=k-1,ans=0;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid,k))r=mid-1,ans=mid;
		else l=mid+1;
	}
	return ans;
}
int Test;
int main(){
	scanf("%d",&Test);
	while(Test--){
		scanf("%d%d",&n,&q);
		for(int i=1;i<=n;++i)a[i]=0,ans[i]=-1;
		for(int i=1;i<=n;++i){
			int x;scanf("%d",&x);
			++a[x];
		}
		for(int i=1;i<=n;++i)s[i]=s[i-1]+a[i];
		for(int i=1;i<=q;++i){
			scanf("%d",&ques[i]);
			if(ans[ques[i]]==-1)ans[ques[i]]=solve(ques[i]);
		}
		for(int i=1;i<=q;++i)
			printf("%d ",ans[ques[i]]);
		puts("");
	}
	return 0;
}

A. Sakurako's Exam

给你若干个数,这些数包括 \(a\) 个 \(1\) 和 \(b\) 个 \(2\),你能在这些数前面添加 \(+\) 或 \(-\) 使其和等于 \(0\),问能否做到。

容易发现我们可以只用关注 \(b\) 对 \(2\) 取模的结果,分类讨论即可

m%=2;
if(m){
    if(n%2==0&&n>=2)puts("YES");
    else puts("NO");
}else{
    if(n%2==0)puts("YES");
    else puts("NO");
}

B. Square or Not

一个漂亮的 \(01\) 矩阵是指数字 \(1\) 全在其外围而数字 \(0\) 全在其内部

img

现在将一个漂亮的 \(01\) 矩阵的字符串形式告诉你,问这个漂亮的 \(01\) 矩阵是否是一个正方形。对于一个大小为 \(r\times c\) 的矩阵,他的字符串 \(s\) 的第 \(((i-1)\times c+j)\) 个元素对应矩形的第 \(i\) 行第 \(j\) 列的元素。

做的时候还把题目看复杂了,以为要判断这个矩阵是不是漂亮的。

容易发现连续的 \(0\) 的数量 \(+2\) 就是这个矩阵的列数,除一下算出行数判断即可。

C. Longest Good Array

一个长为 \(n\) 的数列被认为是好的当且仅当

  • 这个数列是递增的,即 \(a_{i-1}<a_i(2\leq i\leq n)\)。
  • 两个连续数的差也是递增的,即 \(a_i-a_{i-1}<a_{i+1}-a_i(2\leq i<n)\)

现在一直一个好的数列的元素都在 \([l,r]\) 之间,求这个好的数列的最长长度 \((1\leq l\leq r\leq 10^9)\)

显然第一个元素为 \(l\) 是最优秀的,然后按照题意模拟求下一项即可,这是个二次等差数列,第 \(n\) 个数数量级 \(n^2\),足以通过此题。当然也可以求通项再做。

ll l,r;scanf("%lld%lld",&l,&r);
ll v=l,cnt=0;
while(v<=r){
    ++cnt;
    v+=cnt;
}
printf("%lld\n",cnt);

D. Sakurako's Hobby

给定一个排列 \(p\),称一个数 \(j\) 能够从 \(i\) 到达当且仅当可以通过数次 \(i=p_i\) 操作让 \(i\) 等于 \(j\)。排列中的每个数为白色或黑色。定义函数 \(f(i)\) 表示从 \(i\) 可以到达的黑色的数的个数。现在求每个数的 \(f(i)\)

非常典,对 \(i\to p_i\) 连边,可以发现会形成若干个环。\(f(x)\) 就是 \(x\) 所在环中黑色数的个数。实现的话循环染色即可。

int n;scanf("%d",&n);
for(int i=1;i<=n;++i){
    scanf("%d",&p[i]);
    vis[i]=vb[i]=ans[i]=0;
}scanf("%s",s+1);
for(int i=1;i<=n;++i){
    int loc=i,cnt=0;
    while(!vis[loc]){
        vis[loc]=1;
        if(s[loc]=='0')++cnt;
        loc=p[loc];
    }
    loc=i;
    while(!vb[loc]){
        vb[loc]=1;
        ans[loc]=cnt;
        loc=p[loc];
    }
}
for(int i=1;i<=n;++i){
    printf("%d ",ans[i]);
}puts("");

E. Alternating String

如果一个长度为偶数的字符串奇数位的字符相同,偶数位上的字符相同,则称这个字符串为交错串。现在给你一个字符串,求最少通过下列多少次操作可以使字符串变为交错串。

  1. 删去字符串中的一个字符,字符串的长度 \(-1\)。注意:该操作最多只能进行一次。
  2. 选择一个字符将其修改为其他字符。

字符只能包括小写字母。

显然长度为偶数的字符串不进行操作1;长为奇数的字符串必须要进行一次操作1转化为偶数串,并且最先进行操作1不会使答案更劣。

先考虑偶数怎么做,偶数位和奇数位可以分开考虑,对于每种位,将其位上的字符变成这种位上出现次数最多的字符显然最优。开两个桶分别求 \(26\) 种字母在奇数位和偶数位上出现的次数即可。

在考虑奇数怎么做,枚举删除字符的位置,在像偶数做法一样求是 \(O(n^2|S|)\) 的。

可以考虑将删去字符之前的桶和之后的桶整合。考场做法是开一个 \(dp_{i,c,0/1}\) 表示前 \(2\times i\) 个字符中字符 \(c\) 在偶数或奇数位出现的次数(这就是一个前缀和)。

int ans=n,mv1=0,mv2=0;
for(int i=1;i<=n/2;++i){
    mv1=0,mv2=0;
    for(int j=0;j<26;++j){
        mv1=max(mv1,dp[i-1][j][0]+(dp[n/2][j][1]-dp[i-1][j][1]));
        mv2=max(mv2,dp[i-1][j][1]+(dp[n/2+1][j][0]-dp[i][j][0]));
    }
    ans=min(ans,n-mv1-mv2);
    mv1=0,mv2=0;
    for(int j=0;j<26;++j){
        mv1=max(mv1,dp[i][j][0]+(dp[n/2][j][1]-dp[i][j][1]));
        mv2=max(mv2,dp[i-1][j][1]+(dp[n/2+1][j][0]-dp[i][j][0]));
    }
    ans=min(ans,n-mv1-mv2);
}
mv1=0,mv2=0;
for(int j=0;j<26;++j){
    mv1=max(mv1,dp[n/2][j][0]);
    mv2=max(mv2,dp[n/2][j][1]);
}
ans=min(ans,n-mv1-mv2);

现在突然发现可以在枚举断点时就顺带维护前后的桶,码量小而且细节少(没想到复盘这些水题还有一些收获)

int ans=n;
for(int i=1;i<=n;++i)bot[s[i]-'a'][i&1]++;
for(int i=1;i<=n;++i){
    int mv1=0,mv2=0;
    --bot[s[i]-'a'][i&1];
    for(int j=0;j<26;++j){
        mv1=max(mv1,bot2[j][1]+bot[j][0]);
        mv2=max(mv2,bot2[j][0]+bot[j][1]);
    }
    ans=min(ans,n-mv1-mv2);
    ++bot2[s[i]-'a'][i&1];
}
printf("%d\n",ans);

F. Sakurako's Box

给你 \(n\) 个数,求随机去两个数相乘,这个积的期望。

感觉比 E 思维难度小,而且没啥码量,就上床前顺带做了。

求出所有数对的积的和然后除以数对的个数即为期望。定义所有数的和为 \(s\),数对的积的和就是 \(\frac{1}{2}\times\sum a_i\times (s-a_i)\),数对的个数显然 \(\frac{n\times(n-1)}{2}\),求一下逆元即可。

scanf("%d",&n);
ll sum=0,ans=0;
for(int i=1;i<=n;++i){
    scanf("%lld",&a[i]);
    sum=(sum+a[i])%P;
}
for(int i=1;i<=n;++i)
    ans=(ans+a[i]*(sum-a[i]+P)%P)%P;
ans=ans*fpr(2)%P;
printf("%lld\n",ans*fpr(n)%P*fpr(n-1)%P*2%P);

标签:字符,970,int,Codeforces,times,偶数,leq,字符串,Div
From: https://www.cnblogs.com/BigSmall-En/p/18415617

相关文章

  • Codeforces Round 968 (Div. 2)
    传送门A.判断首位字符是否相等即可#include<bits/stdc++.h>usingnamespacestd;constintN=1e6+7;voidsolve(){intn;strings;cin>>n>>s;if(s[0]==s[n-1])cout<<"No"<<endl;elsecout<&l......
  • Codeforces 972 div2
    A-SimplePalindrome1、先对字母进行分配,每个字母分到n/5个2、对剩余字母进行分配,前n%5个字母每一个分配一个3、分别将其输出,相同字母放在一起,如果相同字母分开,就会出现如“ABA”这样的回文子串。AC代码:#include<bits/stdc++.h>usingnamespacestd;charss[7]={......
  • Codeforces Round 972 (Div. 2) 2005C. Lazy Narek 题解
    原题链接:https://codeforces.com/contest/2005/problem/C看了教程发现都是用dp做的,在这里分享一个差不多的SPFA的思路(赛场上忘了Dijkstra不能有负边所以炸了)时间复杂度与dp同样是O(nm)形式化题意和翻译:有n个长度为m的字符串,你可以选择或不选择来拼接它们,但是不能更改字符串的......
  • 【LGR-200-Div.4】洛谷入门赛 #27 A-H题解
    A#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;mt19937rnd(time(0));#defineintlonglongtypedeftuple<int,int,int>tp;#definexfirst#defineysecondtypedefpair<int,int>pii;typedefpair<double,double>......
  • CodeForces VP Record
    CodeForcesRound767(contest1628)AMeximumArray考虑二分。二分的时候计算区间$\text{mex}$,参考P4137RmqProblem/mex,主席树即可。时间复杂度$\Theta(n\log^2n)$,无需卡常。BPeculiarMoviePreferences首先,对于一个合法的回文串,容易证明首尾两个字符串一定......
  • CodeForces 1C - Ancient Berland Circus
    先通过三点确定一条直线,然后算出三条向量的夹角,与圆心角对比,如果呈倍数关系,说明可以接受。特别注意EPS1e-2和1e-7过不了全部数据,改成1e-4通过全部数据。点击查看代码#include<bits/stdc++.h>#definedoublelongdoubleusingnamespacestd;constdoublePI=acos(-1);......
  • 通过注释一行代码 开启关闭一个div的css样式 - 开发调试技巧
    通过注释一行代码开启关闭一个div的css样式-开发调试技巧需求:开发的时候,我需要对页面的某个样式反复开关,但是html不能通过注释来开关,所以可以在div的上面加一个js但是vue的template里面不能加script,需要加component重点代码不写v-bindvscode有红色波浪<componentv-bind:......
  • Pinely Round 2 (Div. 1 + Div. 2)
    A.Channel题意:最开始网上有\(a\)个人,共\(q\)次改变,每一次有一个人加入或离开。总共\(n\)个人,求这\(n\)个人是否都上过网,有没上过网的,都有可能。思路:贪心地每次选取尽可能多和少的人即可。提交记录B.SplitSort题意:给定一个排列,每次可以选取一个数\(x\),将排列划......
  • pbootcms编辑器过滤div代码解决办法
    要在PBootCMS中解决编辑器将<div>标签转换为<p>标签的问题,你可以按照以下步骤操作:修改ueditor.all.js文件:找到core->extend->ueditor->ueditor.all.js文件。定位到大约第10830行,将allowDivTransToP:true改为allowDivTransToP:false。修改ueditor.config.js文件:找到c......
  • 技术深度剖析:ZK 除法中 “Divide and Conquer” 潜藏的漏洞
    在探讨这个主题之前,我们先来了解一下什么是ZK除法以及“DivideandConquer”(分治算法)的基本概念。ZK除法通常是指在零知识证明(Zero-KnowledgeProof,ZK)环境下进行的除法运算。零知识证明是一种密码学技术,允许一方(证明者)向另一方(验证者)证明某个陈述是真实的,而不透露除了该......