VP记录:Codeforces Round 868 (Div. 2) A~D

这篇具有很好参考价值的文章主要介绍了VP记录:Codeforces Round 868 (Div. 2) A~D。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

传送门:CF

A题:A-characteristic

构造一个只有 1 , − 1 1,-1 1,1的数组,满足乘积为 1 1 1的数对的个数为 k k k.
发现 n n n的范围很小,考虑直接暴力枚举数组中 1 1 1的个数,记为 i i i,那么对于1的所有数对来说,我们有 i ∗ ( i − 1 ) / 2 i*(i-1)/2 i(i1)/2个,然后对于 − 1 -1 1的个数也不难表示出为 n − i n-i ni,然后此时的贡献为 ( n − i − 1 ) ∗ ( n − i ) / 2 (n-i-1)*(n-i)/2 (ni1)(ni)/2,判断即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int main() {
	int T=read();
	while(T--) {
		int n=read(),k=read();
		int ans1=-1,ans2=-1;
		for(int i=1;i<=n;i++) {
			int j=n-i;
			if((i-1)*i/2+(j-1)*j/2==k) {
				ans1=i;ans2=j;
				break;
			}
		}
		if(ans1==-1) {
			cout<<"NO"<<endl;
		}
		else {
			cout<<"YES"<<endl;
			for(int i=1;i<=ans1;i++) {
				cout<<"1 ";
			}
			for(int i=1;i<=ans2;i++) {
				cout<<"-1 ";
			}
			cout<<endl;
		}
	}
	return 0;
}

B题:Sort with Step

因为我们只能调换相距为 k k k的数对,那么我们可以将这个数组分为几个轨道,每一个轨道上的数字可以进行交换,不在同一个轨道上的数字不能进行交换.那么假设我们需要进行交换,也肯定是交换不在自己应该在的轨道上的那两个数字.所以我们可以直接记录不在自己应该在的轨道上的数字的个数(记为 k k k).因为我们唯一能使最后序列满足的情况就是将所有数字换到他们应该在的地方.所以当 k k k等于 1 1 1的时候代表其不需要进行初步交换,反之则需要进行 k k k次交换.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];
int main() {
	int T=read();
	while(T--) {
		int n=read(),k=read();
		for(int i=1;i<=n;i++) {
			a[i]=read();
		}
		int cnt=0;int pos=-1;
		for(int i=1;i<=n;i++) {
			if(abs(i-a[i])%k!=0) {
				cnt++;
			}
		}
		if(cnt==0) {
			cout<<0<<endl;
		}
		else {
			if(cnt==2) {
				cout<<1<<endl;
			}
			else {
				cout<<-1<<endl;
			}
		}
	}
	return 0;
}

C题:Strongly Composite

一道需要进行分解质因数的题目.首先我们发现b数组的乘积要和a数组一样.那么不妨将a数组中的乘积进行一个分解质因数,先预处理存起来.显然我们最终b数组的所有数字就是由这些质因数组合而成
然后我们考虑强复合的性质.我们贪心的去想,肯定是用最小个数的质因数来组成一个数字是最优的.所以此时我们有两种组合方式:
1.我们拿两个相同的数来组成一个数 b i bi bi,此时我们的 b i bi bi显然是一个平方数,因为其实由两个质数组合而成,所以此时 b i bi bi显然是一个强复合.
2.显然1方案是最优的方案(因为花费的数字最少).但是此方案需要相同的数字.在1的方案下我们用完了所有的相同的数字,那么此时我们剩下来的就是不同的数字了.我们此时会发现一个很有趣的性质,我们拿出三个质数(记为 i i i, j j j, k k k)乘起来显然是一个强复合.因为两个质数乘起来肯定是一个合数,然后三个质数乘起来显然也是一个合数.又因为质因数的性质,此时我们的因子就是 1 , i , j , k , i ∗ j , i ∗ k , j ∗ k , i ∗ j ∗ k 1,i,j,k,i*j,i*k,j*k,i*j*k 1,i,j,k,ij,ik,jk,ijk,发现恰好是一个强复合数

至此本题也就不难解决了.


本部分介绍一下质因数分解算法的证明,如果熟悉的可以跳过:

for(int j=2;j<=__builtin_sqrt(a[i]);j++) {
	while(temp%j==0) {
		mp[j]++;
		temp/=j;
	}
}		
if(temp!=1) mp[temp]++;

不难发现上述算法只判断到了 n \sqrt{n} n .下面证明一下这个算法的正确性.
首先证明这么做的得到的所有 j j j都是质数:
对于本部分采用反证法进行证明,假设我们当前枚举到的因子 j j j不是一个质数,那么他肯定是一个合数.此时根据唯一分解定理, j j j可以分解成 p 1 k 1 ∗ p 2 k 2 ∗ . . . ∗ p n k n p_1^{k_1}*p_2^{k_2}*...*p_n^{k_n} p1k1p2k2...pnkn这样的形式,那么必然存在 p i < j p_i<j pi<j,但是这样的因子我们在之前枚举到 p i p_i pi时的 w h i l e ( t e m p % j = = 0 ) while(temp\%j==0) while(temp%j==0)已经消掉了,所以不存在这种情况,所以 j j j必然是一个质数
接下来证明一下为什么只需要枚举到 n \sqrt{n} n ,也就是证明一下最后剩下来的那个数字要么是1要么是一个大于 n \sqrt{n} n 的质数
同样采取反证法进行证明,假设最后存在的那个数字k是一个大于 n \sqrt{n} n 的合数.那么根据之前的证明我们会发现这个合数必然是不存在小于 n \sqrt{n} n 的因子的.又因为他是一个合数,所以必然有两个大于 n \sqrt{n} n 的因子,但是此时两个因子相乘得到的数显然比 n n n大,这是不合理的.所以最后剩下来的那个数必然是一个质数
至此证毕


2023.6 update:由于该分解方法复杂度较大,但是 Pollard-rho 分解质因数方法又比较麻烦,所以建议将此方法结合素数筛一起使用,能够大大减少复杂度

void init(int limit=__builtin_sqrt(1e9)) {
	for(int i=2;i<=limit;i++) {
		if(vis[i]) continue;
		prime[++cnt]=i;
		for(int j=i+i;j<=limit;j+=i) {
			vis[j]=1;
		}
	}
}
for(int j=1;j<=cnt;j++) {
	if(temp%prime[j]==0) mp[prime[j]]++;
	while(temp%prime[j]==0) temp/=prime[j];
}
if(temp!=1) mp[temp]++;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define int long long
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];map<int,int>mp;
map<int,int>mp2;
signed main() {
	int T=read();
	while(T--) {
		int n=read();mp.clear();mp2.clear();
		ll sum=1;int cnt=0;int ans=0;
		for(int i=1;i<=n;i++) {
			a[i]=read();int temp=a[i];
			if(a[i]==1) continue;
			for(int j=2;j<=__builtin_sqrt(a[i]);j++) {
				while(temp%j==0) {
					mp[j]++;
					temp/=j;
				}
			}		
			if(temp!=1) mp[temp]++;
		}
		for(auto it : mp) {
			ans+=it.second/2;
			mp[it.first]=it.second-it.second/2*2;
		}
		for(auto it : mp) {
			cnt+=it.second;
		}
		ans+=cnt/3;
		cout<<ans<<endl;
	}
	return 0;
}

D题:Unique Palindromes

首先我们需要知道这样的一个事实,也就是我们每一次在一个字符串的后缀中加上一个任意字符a,我们的回文子串的增加个数最大为1.
简单证明一下这个结论:
我们假设现在有一个字符串为 s s s,那么假设我们此时加上一个 a a a使其增加了回文子串的个数.因为子串是连续的,所以此时我们不妨设多出了两个回文子串 s 1 + a , s 2 + a s1+a,s2+a s1+a,s2+a,并且 s 2 s2 s2 s 1 s1 s1的后缀.不难发现 s 1 + a s1+a s1+a包含了 s 2 + a s2+a s2+a,又因为 s 1 + a s1+a s1+a是一个回文串,所以 s 2 + a s2+a s2+a既是 s 1 + a s1+a s1+a的后缀又是它的前缀.那么此时要么 s 2 + a = = s 1 + a s2+a==s1+a s2+a==s1+a,要么 s 2 + a s2+a s2+a是被 s 2 s2 s2包含的.因为当 s 2 + a s2+a s2+a的长度小于 s 1 + a s1+a s1+a时,又因为是前缀,显然它是被 s 2 s2 s2包含的, s 2 + a s2+a s2+a的长度又不可能大于 s 1 + a s1+a s1+a
至此证毕

所以显然当存在 c [ i ] − c [ i − 1 ] > x [ i ] − x [ i − 1 ] c[i]-c[i-1]>x[i]-x[i-1] c[i]c[i1]>x[i]x[i1]时我们是无法构造的.此处特判一下
然后我们考虑构造,因为ci>3.所以考虑将"abc"作为前缀,当我们此时的c1不够时不断的补上字符"c"来使得其满足.可能会存在回文子串够了但是长度不够的情况.所以我们此时需要补上后缀.此时我们可以反复的补上"abc".举个简单的栗子:
a b c c c    ∣    a b c a b c a abccc\;|\; abcabca abcccabcabca,此时我们会很神奇的发现这样就不会增加回文子串了.
然后我们遇到了后面的回文条件.为了不会和前面已有的字符形成回文子串,我们考虑使用新的字符即可,比如 d , e , f . . . d,e,f... d,e,f....我们发现k<20.所以我们的26个字符是够用的.每一次多增加一个字符我们就可以得到一个贡献,当我们的贡献满时继续使用"abc"填满即可.
注意此时有一个小细节,我们此时的填充需要继续上述的循环,不然可能出现下述情况:ccc    ∣    \;|\; abca    ∣    \;|\; dda,我们会发现会导致意外增加了一个回文子串.

光讲可能比较难以理解,建议结合代码食用文章来源地址https://www.toymoban.com/news/detail-429024.html

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int x[maxn],c[maxn];
int main() {
	int T=read();
	while(T--) {
		int n=read(),k=read();
		for(int i=1;i<=k;i++) x[i]=read();
		for(int i=1;i<=k;i++) c[i]=read();
		int flag=0;
		for(int i=1;i<=k;i++) {
			if(c[i]-c[i-1]>x[i]-x[i-1]) {
				flag=1;
				break;
			}
		}
		if(flag==1) {
			cout<<"NO"<<endl;
			continue;
		}
		vector<char>ans;char kkk='c';
		ans.push_back('a');ans.push_back('b');ans.push_back('c');
		int pos=4;int hhh=3;char loop='a';
		for(int i=1;i<=k;i++) {
			if(i==1) {
				while(pos<=x[i]) {
					if(pos<=c[i]) {
						ans.push_back('c');
					}
					else {
						ans.push_back(loop);
						loop++;
						if(loop=='d') loop='a';
					}
					pos++;
				}
			}
			else{
				while(pos<=x[i]) {
					if(x[i]-pos+1>c[i]-c[i-1]) {//先达成条件再补长度
						ans.push_back(loop);
						loop++;
						if(loop=='d') loop='a';
					}
					else {
						ans.push_back('c'+i-1);
					}
					pos++;
				}
			}
			
		}
		cout<<"YES"<<endl;
		for(int i=0;i<ans.size();i++) cout<<ans[i];
		cout<<endl;
	}
	return 0;	
}

到了这里,关于VP记录:Codeforces Round 868 (Div. 2) A~D的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Codeforces Round 868 (Div. 2) F. Random Walk(树上期望)

    题目 n(n=2e5)个点的树, 从起点s出发,每次等概率选择一条边,随机游走到相邻点 若走到t,则停止,问每个点经过的期望次数,答案对998244353取模 思路来源 DLUT_Zeratul讲解 题解 需要分成三部分考虑, ①s-t这条链,将这条链上的边定向,经过的次数,正向边=反向边+1 ②对于

    2024年02月12日
    浏览(33)
  • [补题记录] Codeforces Round 906 (Div. 2)(A~D)

    URL:https://codeforces.com/contest/1890 目录 A Problem/题意 Thought/思路 Code/代码 B Problem/题意 Thought/思路 Code/代码 C Problem/题意 Thought/思路 Code/代码 D Problem/题意 Thought/思路 Code/代码 给出一个数组 A,你可以将它任意排列,问是否能使得  化简题目给的要求,我们可以发现: a1 = a3、a3

    2024年02月06日
    浏览(43)
  • Codeforces Round 920 (Div. 3)

    Codeforces Round 920 (Div. 3) 题意:随机给出正方形在平面坐标系上的四个顶点的坐标,求正方形的面积,正方形边与xy轴平行。 思路:因为正方形与坐标轴平行,所以找出相同的两x或y坐标即可找到一条边的长度,平方就是面积,注意结果返回整型。 AC code: 题意:给出两个01字符

    2024年01月17日
    浏览(57)
  • Codeforces Round 866 (Div. 2)

    给出一个仅由_或^组成的字符串,你可以在任意位置添加_或^字符,使得字符串满足: 任意字符要么属于^_^的一部分,要么属于^^的一部分。求最少添加的字符数量。 对于_我们只需处理没有组成^_^的_: ①如果_在首位置且左边没有^则添加^ ②如果_在尾位置且右边没有^则添加

    2023年04月25日
    浏览(54)
  • Codeforces Round 926 (Div. 2)

    类似于倍投法,就是在一赔一的情况下,第一次压一块钱,每输一次就押注上一次两倍的金额. 假如资金无限的话,这种方法赢的期望为无穷大.原理类似于二进制,不论你输再多次,只要赢一次总额就增加了1.比如 15 二进制1111,前3把一直输,但是只要第4把赢,就一定可以增加 1

    2024年02月20日
    浏览(43)
  • Codeforces Round 874 (Div. 3)

    用最少的长度为2的字符串按一定规则拼出s。规则是:前一个字符串的尾与后一个字符串的首相同。 统计s中长度为2的不同字符串数量。 给定数组a[n]和b[n],重排b后,令任意|ai−bi|≤k成立(1≤k≤n)数据保证一定有解。 将a和b分别按从小到大的顺序匹配便是最优的,一定能满足

    2024年02月05日
    浏览(36)
  • Codeforces Round 871 (Div. 4)

    给定n个长度为10的字符串,问其与codeforces字符串的对应下标字母不同的个数。 对于每个字符串从前往后依次和“codeforces”对应字符比较然后统计不同字母数即可 给定长度为n的数组,问连续相邻为0的最大长度 维护一个全局最大长度res,和当前连续序列的长度cnt。从前往后扫

    2024年02月03日
    浏览(51)
  • Codeforces Round 867 (Div. 3)

    从所有a[i]+i-1=t的选择种取个max即可 实际上就是取同符号乘积的最大值 找规律,发现结果与边长n的关系是:res = n * (n + 3) - (n - 2) ①当n为奇数时,除了1其他均无解 ②当n为偶数时,我们可以构造一个形如n,1,n - 2,3,...的数列 首先我们可以发现n必定出现在起始位置。如果n不在起

    2024年02月02日
    浏览(45)
  • Codeforces Round 881 (Div. 3)

    给定一个数组,给每个元素涂色。求最大的代价。 代价为每个颜色的代价和。 每个颜色的代价为涂了该颜色的元素的极差。 因为是极差,每个元素要么对答案有正的贡献,要么有负的贡献,要么无贡献。且正负贡献的个数要相同。 因为要最大值,自然就是想有正贡献的是最

    2024年02月09日
    浏览(41)
  • Codeforces Round 912 (Div. 2)

    大等于2依据冒泡排序即可排序,因此判断下1即可 对每一个数字找哪一位肯定为0填0其他的填1 从后往前考虑加到当前集合或新立一个集合 从最高位开始考虑能否为1,计算能否时每个数当前位为1

    2024年02月04日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包