Codeforces Round #747 (Div. 2)题解

Codeforces Round #747 (Div. 2)题解

(本博客将持续更新以后每场CF div2的题解,喜欢ACM、OI的小伙伴记得点个关注哟)
昨天夜晚刷网络流刷入迷了,渐渐就忘记了我还要打CF,直到洗澡的时候才想起来。说好以后每场要打的,我当然不能食言啦。这不,今早起来把这场的题给补了。
话不多说,看题解:

A. Consecutive Sum Riddle
描述:
Theofanis has a riddle for you and if you manage to solve it, he will give you a Cypriot snack halloumi for free (Cypriot cheese).

You are given an integer n. You need to find two integers l and r such that −1018≤l<r≤1018 and l+(l+1)+…+(r−1)+r=n.

Input
The first line contains a single integer t (1≤t≤104) — the number of test cases.

The first and only line of each test case contains a single integer n (1≤n≤1018).

Output
For each test case, print the two integers l and r such that −1018≤l<r≤1018 and l+(l+1)+…+(r−1)+r=n.

It can be proven that an answer always exists. If there are multiple answers, print any.

中文题意:给你一个整数,把他拆成若干个连续整数的和。
思路:
这是一个构造题目,显然当 n=2k+1 时我们可以将n拆成k与k+1,但是当n是偶数的时候这样却行不通。仔细审题我们发现所有数都可以取long long范围内的任何数(包括负数),于是我们自然而然地想到利用正和负相互抵消,
即 n=-(n-1)-(n-2)-(n-3)-…-2-1+0+1+2+…+(n-3)+(n-2)+(n-1)+n.
这种正负相互抵消的对称构造法在序列题里面是经常出现的。
代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\n' 
using namespace std;

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T,x;cin>>T;
	while(T--){
		cin>>x;
		cout<<-x+1<<" "<<x<<endl;
	} 
	return 0;
}

B. Special Numbers
描述:
Theofanis really likes sequences of positive integers, thus his teacher (Yeltsa Kcir) gave him a problem about a sequence that consists of only special numbers.

Let’s call a positive number special if it can be written as a sum of different non-negative powers of n. For example, for n=4 number 17 is special, because it can be written as 40+42=1+16=17, but 9 is not.

Theofanis asks you to help him find the k-th special number if they are sorted in increasing order. Since this number may be too large, output it modulo 109+7.

Input
The first line contains a single integer t (1≤t≤104) — the number of test cases.

The first and only line of each test case contains two integers n and k (2≤n≤109; 1≤k≤109).

中文题意:
输入n和k,求第k大的n进制表示形式中仅含有1和0的数。
思路:我们可以把k化成2进制,然后求这个数在n进制下的值(独立思考一下为什么)。
代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int mod=1e9+7;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--){
		int n,k,ans=0,p[40]={1};
		cin>>n>>k;
		for(int i=1;i<40;i++) p[i]=p[i-1]*n%mod;
		for(int i=0;k;i++){
			if(k&1) ans+=p[i];
			k>>=1; 
		}
		ans%=mod;
		cout<<ans<<endl;
	} 
	return 0;
}

C. Make Them Equal
描述:
Theofanis has a string s1s2…sn and a character c. He wants to make all characters of the string equal to c using the minimum number of operations.

In one operation he can choose a number x (1≤x≤n) and for every position i, where i is not divisible by x, replace si with c.

Find the minimum number of operations required to make all the characters equal to c and the x-s that he should use in his operations.

Input
The first line contains a single integer t (1≤t≤104) — the number of test cases.

The first line of each test case contains the integer n (3≤n≤3⋅105) and a lowercase Latin letter c — the length of the string s and the character the resulting string should consist of.

The second line of each test case contains a string s of lowercase Latin letters — the initial string.

It is guaranteed that the sum of n over all test cases does not exceed 3⋅105.

Output
For each test case, firstly print one integer m — the minimum number of operations required to make all the characters equal to c.

Next, print m integers x1,x2,…,xm (1≤xj≤n) — the x-s that should be used in the order they are given.

It can be proved that under given constraints, an answer always exists. If there are multiple answers, print any.

中文题意:给你一个长为n的序列,你可以每次执行如下操作:选定一个1~n之间的数x,将所有不被x
整除的元素给为c。问最少需要几次操作才能使所有元素都变成c?

思路:又是一道序列题,如果敢于大胆猜想,那么这道题将比前一道更加简单。既然是在1~n内选一个除数,那么一般情况下肯定是越大越好。比如说我们如果选了n,显然比n小的数是不可能整除n的,所以1到n-1内的数就全被变成c了,然后最多再选一个不是n的因子的数就能把第n个数变成c了。因此,最多选两个数即可完成要求。(如果小于n的数都是n的除数呢?这是不可能的,因为对于n>=3,n-1必不可能是n的除数)。
我们还要再明确一个性质,那就是选小于等于n/2的数肯定是不优的,因为对于这样的一个数x<=n/2,必有2x<=n,选2x显然更好。
于是,我们可以分两类情况:
1.一次操作即可完成:选一个(n/2,n]且为c的数。
2.两次操作即可完成:选n-1和n。
代码如下:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int vis[300010];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--){
		int n,flag=1;char a;string s;
		cin>>n>>a>>s;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=n;i++){
			if(s[i-1]!=a){
				vis[i]=1;
				flag=0;	
			} 
		}
		if(flag)
		{
			cout<<0<<endl;
			continue;
		}
		for(int i=n;i>n/2;i--){
			if(!vis[i])
			{
				cout<<1<<endl<<i<<endl;
				goto xiaobo;
			}
		}
		cout<<2<<endl<<n-1<<' '<<n<<endl;
		xiaobo:;
	} 
	return 0;
}

D. The Number of Imposters
time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Theofanis started playing the new online game called “Among them”. However, he always plays with Cypriot players, and they all have the same name: “Andreas” (the most common name in Cyprus).

In each game, Theofanis plays with n other players. Since they all have the same name, they are numbered from 1 to n.

The players write m comments in the chat. A comment has the structure of “i j c” where i and j are two distinct integers and c is a string (1≤i,j≤n; i≠j; c is either imposter or crewmate). The comment means that player i said that player j has the role c.

An imposter always lies, and a crewmate always tells the truth.

Help Theofanis find the maximum possible number of imposters among all the other Cypriot players, or determine that the comments contradict each other (see the notes for further explanation).

Note that each player has exactly one role: either imposter or crewmate.

Input
The first line contains a single integer t (1≤t≤104) — the number of test cases. Description of each test case follows.

The first line of each test case contains two integers n and m (1≤n≤2⋅1e5 ,0≤m≤5⋅10^5) — the number of players except Theofanis and the number of comments.

Each of the next m lines contains a comment made by the players of the structure “i j c” where i and j are two distinct integers and c is a string (1≤i,j≤n; i≠j; c is either imposter or crewmate).

There can be multiple comments for the same pair of (i,j).

It is guaranteed that the sum of all n does not exceed 2⋅105 and the sum of all m does not exceed 5⋅10^5

Output
For each test case, print one integer — the maximum possible number of imposters. If the comments contradict each other, print −1.

中文题意:给你n个人,m句话,每句话所表达的意思分两种:a认为b说谎,或者a认为b不说谎。
问最多能有几个人说谎。
思路:易见,若a不说谎,则a认为b说谎等价于b说谎,a认为b不说谎等价于b不说谎;若a说谎,则a认为b说谎等价于b不说谎,a认为b不说谎等价于a说谎。
归纳起来就是,若a认为b说谎,则a与b恰好相反,若a认为b不说谎,则a与b恰好相同。
于是,输入中给出的m个语句告诉了我们点与点之间的相同与不同关系。
那么这题怎么解呢?我们需要两个前置知识(方法):
1.如何处理这些自反、可传递的关系?没错,用并查集。
2.遇到逻辑关系怎么办?利用two set里面的技巧(不会也没有关系),把一个点拆成两个状态:真、假(拆点的技巧很常用,网络流什么的经常干)。若两个点a和b状态相反,则a0与b1连边,a1与b0连边;反之则a0与b0连边,a1与b1连边。
(a0是a的假值状态,a1是a的真值状态)。
最后对于每个连通块(每个并查集)统计多数点的状态就行了(要有对称的思想)。
代码:

#include<bits/stdc++.h>
using namespace std; 
int fa[400005],cnt[400005][2];
inline int find(int x) {
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x, int y) {
    fa[find(x)]=find(y);
}
void solve(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n+n;i++) fa[i]=i;
    while(m--){
        int u,v;
        char s[15];
        scanf("%d %d %s",&u,&v,s);
        if(s[0]=='i') merge(u,v+n),merge(u+n,v);
        else merge(u,v),merge(u+n,v+n);
    }
    for(int i=1;i<=n;i++){
		if(find(i)==find(i+n)){
        	puts("-1");
        	return ;
    	}	
	}
    for(int i=1;i<=n+n;i++) cnt[i][0]=cnt[i][1]=0;
    for(int i=1;i<=n+n;i++) cnt[find(i)][i<=n]+=1;
    int ans=0;
    for(int i=1;i<=n+n;i++){
		if(find(i)==i) ans+=max(cnt[i][0],cnt[i][1]);	
	} 
    printf("%d\n",ans>>1);
}

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

E1. Rubik’s Cube Coloring (easy version)
描述:
It is the easy version of the problem. The difference is that in this version, there are no nodes with already chosen colors.

Theofanis is starving, and he wants to eat his favorite food, sheftalia. However, he should first finish his homework. Can you help him with this problem?

You have a perfect binary tree of 2k−1 nodes — a binary tree where all vertices i from 1 to 2k−1−1 have exactly two children: vertices 2i and 2i+1. Vertices from 2k−1 to 2k−1 don’t have any children. You want to color its vertices with the 6 Rubik’s cube colors (White, Green, Red, Blue, Orange and Yellow).

Let’s call a coloring good when all edges connect nodes with colors that are neighboring sides in the Rubik’s cube.

A picture of Rubik’s cube and its 2D map.
More formally:

a white node can not be neighboring with white and yellow nodes;
a yellow node can not be neighboring with white and yellow nodes;
a green node can not be neighboring with green and blue nodes;
a blue node can not be neighboring with green and blue nodes;
a red node can not be neighboring with red and orange nodes;
an orange node can not be neighboring with red and orange nodes;
You want to calculate the number of the good colorings of the binary tree. Two colorings are considered different if at least one node is colored with a different color.

The answer may be too large, so output the answer modulo 109+7.

Input
The first and only line contains the integers k (1≤k≤60) — the number of levels in the perfect binary tree you need to color.

Output
Print one integer — the number of the different colorings modulo 109+7.

中文题意:用六中颜色给一个高度为k的完美二叉树染色,每两个相邻点的颜色必须是魔方中的一组相邻色,问有几种染色方法。
思路:很简单的组合数学题(或者说很简单的dp)。每个高为k的完美二叉树由两颗高为k-1的二叉树和一个顶点组成,枚举顶点的颜色,当顶点颜色确定后,他的子树的顶点颜色只有4中选择,也就是有dp[k-1]*4/6种。于是有dp[k]=6×(dp[k-1]×4/6)×(dp[k-1]×4/6)。
代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int mod=1e9+7;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int k;
	cin>>k;
	int a[100];
	a[1]=1;
	for(int i=2;i<100;i++){
		a[i]=a[i-1]*a[i-1]%mod*16%mod;
	}
	cout<<6*a[k]%mod<<endl;
	return 0;
}

E2. Rubik’s Cube Coloring (hard version)
不会写,哈哈哈(有谁能教教我吗?)

F. Ideal Farm
描述:
Theofanis decided to visit his uncle’s farm. There are s animals and n animal pens on the farm. For utility purpose, animal pens are constructed in one row.

Uncle told Theofanis that a farm is lucky if you can distribute all animals in all pens in such a way that there are no empty pens and there is at least one continuous segment of pens that has exactly k animals in total.

Moreover, a farm is ideal if it’s lucky for any distribution without empty pens.

Neither Theofanis nor his uncle knows if their farm is ideal or not. Can you help them to figure it out?

Input
The first line contains a single integer t (1≤t≤105) — the number of test cases.

The first and only line of each test case contains three integers s, n, and k (1≤s,n,k≤1018; n≤s).

Output
For each test case, print YES (case-insensitive), if the farm is ideal, or NO (case-insensitive) otherwise.

中文题意:给你一个总和s,一个整数n,一个部分和k,问是否所有的长为n且和为s的正整数序列是否都都存在某个子段的和为k?
思路:这个题的题意理解还是不难的,但是具体怎么解却不大好办。
我们可以考虑它的相反面,尽量构造一个没有子段的和等于k的序列。首先我们需要一个前置知识,那就是用前缀和的差来表示子段和。
设数组a的前缀和数组为s,
若s1,s2,s3,sn中不存在i<j使得s[i]+k=s[j]且不存在任何一个s[x]等于k,则这个前缀和数组的构造是成功的。
一个前缀和数组可以唯一地换原而且必能换原成一个a[]数组(有一个性质叫原数组和前缀和数组时一一对应的)。
于是,我们考虑能否从1,2,3,,,,s中挑选n个数,使得这n个数两两间的差不为k且没有数等于k。
方法就很简单了,我们将s个数每k个分成一组,只取奇数组的数就可以了(注意,k这一个元素不能取)。
代码如下(代码中有一个奇怪的地方就是判k的):

#include<bits/stdc++.h>
#define int long long
using namespace std;
 
void solve(){
	int s,n,k,ans=0;
	scanf("%lld %lld %lld",&s,&n,&k);
	if(s==k)
	{
		puts("YES");
		return;
	}
	ans=s/(2*k)*k;
	s%=2*k;
	ans+=min(k,s+1);
	puts(ans>n?"NO":"YES");
}
signed main(){
    int T;cin>>T;
    while(T--)  solve();
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

组合,我有特殊的计数技巧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值