Codeforces 891 div3 A-G

A. Array Coloring

分析

元素和为偶数才可以让两种颜色的元素的奇偶性相同(奇+奇=偶,偶+偶=偶)

奇=奇+偶

C++代码

#include<iostream>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int n,sum=0;
		cin>>n;
		for(int i=0;i<n;i++){
			int x;
			cin>>x;
			sum+=x;
		}
		if(sum&1)puts("NO");
		else puts("YES");
	}
	return 0;
} 

B. Maximum Rounding

分析

从大到小枚举数的每一位,如果当前位置可以进位,则一直往前进位直到不能进位,然后break,每次记录当前在哪里进位的,它后面的所有数都变成0,前面的不变

C++代码

#include<iostream>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		string s;
		cin>>s;
		s='0'+s;
		int flag=1e9;//flag记录最后一次进位的位置
		for(int i=1;i<s.size();i++){
			if(s[i]>='5'){
				int j=i;
				while(j>=1&&s[j]>='5'){//当前位置可以进位,则一直往前进,直到不能进位
					s[j-1]++;
					flag=j;
					j--;
				}
				break;
			}
		}
		if(flag==1)cout<<s[0];//最后一次进位在最高位
		for(int i=1;i<s.size();i++){
			if(i>=flag)cout<<0;//最后一次进位的位置往后的数字全都变成0
			else cout<<s[i];//否则就直接输出
		}
		cout<<endl;
	}
	return 0;
}

C. Assembly via Minimums

分析

由题意,最小的数在序列中一定出现了n-1次,第二小的数出现n-2次,以此类推...

最大的数出现了0次,但是可以发现,如果最大的数等于次大的数,不会影响结果

然后用小根堆记录每个数,然后最小的数出队n-1次,因为一共有n-1个最小的数,第二小的数出队n-2次,...,把每个数存下来就OK了,然后记得加一个最大的数,直接加上次大的数就可以了

C++代码

#include<iostream>
#include<queue>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int n,x;
		cin>>n;
		int a[n+5]={0};
		int m=n*(n-1)/2;
		priority_queue<int,vector<int>,greater<int>> heap;//小根堆
		for(int i=1;i<=m;i++){
			cin>>x;
			heap.push(x);
		}
		vector<int> ans;
		for(int i=n-1;i>0;i--){
			int t=heap.top(),j=i;
			while(j--)heap.pop();
			ans.push_back(t);
		}
		ans.push_back(ans.back());//加上最大的数
		for(int i=0;i<ans.size();i++)cout<<ans[i]<<" ";
		cout<<endl;
	} 
	return 0;
}

D. Strong Vertices

分析

a[i]-b[i]>=a[j]-b[j],则i~j有一条边

令c[i]=a[i]-b[i],即c[i]>=c[j]则表示i~j有一条边

所以找出数组c中最大的数,最大的数一定可以向其他的所有点连一条边,即为题中所说强顶点,找出最大的数有几个即可

C++代码

#include<iostream>
#include<vector>
using namespace std;
const int N=200010;
int a[N],b[N],c[N];
void solve(){
	int n,maxx=-2e9;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int j=1;j<=n;j++)cin>>b[j];
	for(int i=1;i<=n;i++){
		c[i]=a[i]-b[i];
		maxx=max(maxx,c[i]);
	}
	vector<int> ans;
	for(int i=1;i<=n;i++){
		if(c[i]==maxx)ans.push_back(i);
	}
	cout<<ans.size()<<endl;
	for(int i=0;i<ans.size();i++)cout<<ans[i]<<" ";
	cout<<endl;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

E. Power of Points

分析

每个点的fp就是以该点为一个端点与其他所有点组成的区间覆盖的点数之和

然后要挖掘性质了,举例子:1,2,5,7(有序序列)

每个点为端点与它本身都有一个区间覆盖的点数为1,所以先不算这个1

以2为一个端点,区间为[1,2],[2,5],[2,7]

点数之和为2+4+6=12

下一个数是5,以5为一个端点的区间为[1,5],[2,5],[5,7]

点数之和为5+4+3=12,与上式对比发现,2前面所有点覆盖的点数+3,5后面所有点覆盖的点数-3

观察一下这两个式子,发现每次以一个数a[i]为端点时,假设当前点与上一个点a[i-1]的差距为gap

则sum[i]=sum[i-1]+(i-2)*gap-(n-i)*gap;

C++代码

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
const int N=200010;
typedef long long LL; 
int a[N],b[N];
int n;
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i];//b[i]把原始的a[i]存起来
	sort(a+1,a+1+n);//从小到大排序
	LL sum=1;//sum初始化为1,每个数为端点首先覆盖自己这个点
	for(int i=2;i<=n;i++)sum+=a[i]-a[1]+1;//先把第一个数为一个端点的sum算出来
	map<int,LL> mp;//map记录答案
	mp[a[1]]=sum;
	for(int i=2;i<=n;i++){
		int gap=a[i]-a[i-1];
		sum=sum+(LL)(i-2)*gap-(LL)(n-i)*gap;
		mp[a[i]]=sum;
	}
	for(int i=1;i<=n;i++)cout<<mp[b[i]]<<" ";
	cout<<endl;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

F. Sum and Product

分析

a[i]+a[j]=x,a[i]*a[j]=y

即a[i]*(x-a[i])=y,化简得a[i]^2-x*a[i]+y=0,即a^2-x*a+y=0

问题就变成了该方程组有几组解

delta=x^2-4*y

记录数组a中每个数的个数,用cnt记录

如果delta<0,则无解

否则有解,求出a1和a2

1、a1==a2,答案就是cnt[a1]*(cnt[a1]-1)/2

2、a1!=a2,答案就是cnt[a1]*cnt[a2]

C++代码

#include<iostream>
#include<map>
#include<vector>
#include<cmath>
using namespace std;
const int N=200010;
typedef long long LL;
LL a[N];
void solve(){
    map<LL,LL> cnt;
    int n,q;
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		cnt[x]++;
	}
    cin>>q;
    while(q--){
        LL x,y;
        cin>>x>>y;
        LL delta=x*x-4*y;
        if(delta<0){
            cout<<0<<" ";
			continue;
        }
        LL s=sqrtl(delta);
        LL x1=(x-s)/2,x2=(x+s)/2;
        if(x1+x2!=x||x1*x2!=y){
            cout<<0<<" ";
			continue;
        }
        if(x1==x2)cout<<cnt[x1]*(cnt[x1]-1)/2<<" ";
        else cout<<cnt[x1]*cnt[x2]<<" ";
    }
    cout<<endl;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

G. Counting Graphs

分析

将所有边按照权值进行从小到大排序

然后按顺序枚举所有边,每次找到当前边连接的两点a,b所在连通块中分别有多少个点cnt[a],cnt[b]

此时可以加的边数为cnt[a]*cnt[b]-1(减去a-b本身)

边的权值有S-w+1种情况,首先是[w+1,s],其次还可以不加边,所以有s-w+1种情况

所以对于条边,对答案的贡献为(S-w+1)^(cnt[a]*cnt[b]-1)

枚举完每条边,就要将两个点合并到一个连通块中

C++代码

#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=200010,mod=998244353;
int p[N],cnt[N];
int n,S;
struct Node{
	int u,v,w;
	bool operator<(const Node &W)const
	{
		return w<W.w;//按照w的值进行排序
	}
}edges[N];
int idx;
int find(int x){
	if(p[x]!=x)p[x]=find(p[x]);
	return p[x];
}
int qmi(int a,int k,int p){//快速幂求a^k%p的值
	int res=1;
	while(k){
		if(k&1)res=res*a%p;
		a=a*a%p;
		k>>=1;
	}
	return res;
}
void solve(){
	scanf("%d%d",&n,&S);
	for(int i=1;i<=n;i++)p[i]=i,cnt[i]=1;//并查集 
	idx=0;
	for(int i=1;i<n;i++){
		int u,v,w;
		cin>>u>>v>>w;
		edges[idx++]={u,v,w};
	}
	sort(edges,edges+idx);
	int ans=1;
	for(int i=0;i<idx;i++){
		int a=edges[i].u,b=edges[i].v,w=edges[i].w;
		a=find(a),b=find(b);
		ans=ans*qmi(S-w+1,cnt[a]*cnt[b]-1,mod)%mod;
        //将a,b所在连通块合并
		p[a]=b,cnt[b]+=cnt[a];
	}
	printf("%d\n",ans);
}
signed main(){
	int t;
	scanf("%d",&t);
	while(t--){
		solve();
	}
	return 0;
}

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值