Codeforces Round #730 (Div. 2)
A. Exciting Bets(补)
思路点拨
题意
求max(gcd(a+n,b+n))
以及偏移的距离n
思路
我们假设 a>=b
,gcd(x,0)=x (x>=0)
则有gcd(a,b)=gcd(a,a-b)
证明过程
因为无论如何操作,a-b
都是固定不变的
所以max(gcd(a+n,b+n)) = max(gcd(a+n,a-b))
显然这个数为a-b
所以先特判,当a=b
输出0 0
否则,我们只需要找到a-b
的倍数中距离a
较近的两个数s1 s2
n1=abs(s1-a)=a%(a-b)
n2=abs(s2-a)=a-b-a%(a-b)
所求的 n=min(n1,n2)
参考代码
// Problem: A. Exciting Bets
// Contest: Codeforces - Codeforces Round #730 (Div. 2)
// URL: https://codeforces.com/contest/1543/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,n;
int main()
{
cin>>n;
while(n--){
cin>>a>>b;
if(a==b){
printf("0 0\n");continue;
}
if(a<b) swap(a,b);
printf("%lld %lld\n",a-b,min(a%(a-b),a-b-a%(a-b)));
}
}
B. Customising the Track
思路点拨
题意
给定一个数组a
,你可以随意增减a[i]
的值使得数组总和不变,前提是增减后的a[i]
都非负,求
∑
i
=
1
n
∑
j
=
i
+
1
n
∣
a
i
−
a
j
∣
\sum_{i=1}^{n}\sum_{j=i+1}^{n}{|a_i-a_j|}
∑i=1n∑j=i+1n∣ai−aj∣的最小值
思路
设数组a
的总和为 sum
平均数为 ave=sum/n
,我们要让尽可能让更多的数接近平均数
那数组就会变成 sum%n
个ave和 n-sum%n
个ave+1
的新数组
又会变成 sum%n
个0 和 n-sum%n
个1
的新数组
那结果就是 (n-sum%n)*(sum%n)
参考代码
// Problem: B. Customising the Track
// Contest: Codeforces - Codeforces Round #730 (Div. 2)
// URL: https://codeforces.com/contest/1543/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,a[200010],sum;
int main()
{
cin>>t;
while(t--){
cin>>n;
sum=0;
for(int i=0;i<n;i++)
cin>>a[i],sum+=a[i];
printf("%lld\n",(n-sum%n)*(sum%n));
}
}
Codeforces Round #731 (Div. 3)
A. Shortest Path with Obstacle
思路点拨
题意
给你A
,B
,F
的坐标,其中F
为陷阱,不能走
求A
到B
的最近距离
思路
不难发现规律:当ABF
不在同一行且不在同一列时,F
对AB
最短距离无影响
当ABF
在同一行或同一列时,只要在最短距离的基础上绕过F(+2)
即可
参考代码
// Problem: A. Shortest Path with Obstacle
// Contest: Codeforces - Codeforces Round #731 (Div. 3)
// URL: https://codeforces.com/contest/1547/problem/A
// Memory Limit: 512 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
int t,a1,a2,b1,b2,f1,f2;
int main()
{
cin>>t;
while(t--){
cin>>a1>>a2>>b1>>b2>>f1>>f2;
if(a1==b1&&f1==a1){
if((f2>a2&&f2<b2)||(f2>b2&&f2<a2)) cout<<abs(a1-b1)+abs(a2-b2)+2<<endl;
else cout<<abs(a1-b1)+abs(a2-b2)<<endl;
}
else if(f2==a2&&a2==b2){
if((f1>a1&&f1<b1)||(f1>b1&&f1<a1)) cout<<abs(a1-b1)+abs(a2-b2)+2<<endl;
else cout<<abs(a1-b1)+abs(a2-b2)<<endl;
}
else cout<<abs(a1-b1)+abs(a2-b2)<<endl;
}
}
B. Alphabetical Strings
思路点拨
题意
S
是空字符串,我们可以在S
的开头或结尾按字母表顺序添加若干字母形成新S
,再在新S
的基础上重复上述操作。
现在给出若干字符串,判断字符串是否满足上述规则。
思路
根据题意模拟判断即可
参考代码
// Problem: B. Alphabetical Strings
// Contest: Codeforces - Codeforces Round #731 (Div. 3)
// URL: https://codeforces.com/contest/1547/problem/B
// Memory Limit: 512 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
bool isa(string &s){
int len=s.length(),o;
char c='a';
if(s.find(c)!=string::npos) o=s.find(c);
else return false;
int p=o-1,q=o+1;
c=(char)c+1;
for(;p>=0||q<len;p--,q++){
if(p>=0&&s[p]==c){
c=(char)c+1;
q--;
}
else if(q<len&&s[q]==c){
c=(char)c+1;
p++;
}
else return false;
}
return true;
}
int main()
{
cin>>n;
while(n--){
cin>>s;
if(isa(s)) puts("YES");
else puts("NO");
}
}
C. Pair Programming
思路点拨
题意
第一行给你三个数k
,a
,b
k
表示初始的文件行数
a
,b
表示M和P一共工作了a+b分钟
第二行是序列1的操作,从a[1],a[2],a[3],...a[n]
,当a[i]=0
,那么M
在文件的最后一行添加一行,当a[i]>0
,那么M
将修改第a[i]
行,前提是文件行数>=a[i]
,否则就是非法操作
第三行是序列2的操作,从b1,b2,b3,...bn
,操作过程同上
M
和P
分别只能按照a[1]-a[n]
,b[1]-b[n]
的顺序执行操作,但是M
和P
可以任意交替操作,比如a[1]
,b[1]
,a[2]
,a[3]
,b[2]
对于每个测试用例,如果有合法操作的话则输出长度为n+m
的合法操作,否则输出-1
思路
思路:利用双指针同时左往右遍历,在未越界的前提下,贪心地优先在文件末尾添加新行,其次寻找两个当中的较小的,判断较小的是否合法。
参考代码
// Problem: C. Pair Programming
// Contest: Codeforces - Codeforces Round #731 (Div. 3)
// URL: https://codeforces.com/contest/1547/problem/C
// Memory Limit: 512 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
int t,k,n,m,sum,nummax;
int a[110],b[110],c[220];
int posc;
bool istrue(){
int posa=0,posb=0;posc=0;
for(;posa<n||posb<m;){
if(posa<n&&posb<m){
if(!a[posa]) c[posc++]=0,posa++,k++;
else if(!b[posb]) c[posc++]=0,posb++,k++;
else if(min(a[posa],b[posb])>k) return false;
else if(a[posa]<=b[posb]) c[posc++]=a[posa++];
else c[posc++]=b[posb++];
}
else if(posa<n){
if(!a[posa]) c[posc++]=0,posa++,k++;
else if(a[posa]>k) return false;
else c[posc++]=a[posa++];
}
else if(posb<m){
if(!b[posb]) c[posc++]=0,posb++,k++;
else if(b[posb]>k) return false;
else c[posc++]=b[posb++];
}
}
return true;
}
int main()
{
cin>>t;
while(t--){
cin>>k>>n>>m;
sum=0,nummax=0;
for(int i=0;i<n;i++){
cin>>a[i];
if(!a[i]) sum++;
nummax=max(a[i],nummax);
}
for(int i=0;i<m;i++){
cin>>b[i];
if(!b[i]) sum++;
nummax=max(b[i],nummax);
}
if(k+sum<nummax) puts("-1");
else{
if(istrue()){
printf("%d",c[0]);
for(int i=1;i<posc;i++)
printf(" %d",c[i]);
puts("");
}
else puts("-1");
}
}
}
Educational Codeforces Round 111 (Rated for Div. 2)
A. Find The Array
思路点拨
题意
对于数组a
,如果对于从 1
到 n
的每个 i
都满足a[i]=1
,或者至少存在数字a[i]-1
或a[i]-2
在数组a
中,则称数组 a
是美丽的。
现给你t
个数,对于每个正整数s
,找到数组各元素总和等于 s
的美丽数组的最小长度
思路
如果美丽数组升序排列,则有如下规律
在[a1,a2,a3,a4,a5......]
中
要么 a1=a2=a3=a4=a5=......=1
要么a1=1,a2∈[2,3],a3∈[4,5],a4∈[6,7],a5∈[8,9]......
因为我们要找出最小长度,所以优先选择第二种
则其前缀和s
在
(
(
n
−
1
)
∗
(
n
−
1
)
,
n
∗
n
]
((n-1)*(n-1),n*n]
((n−1)∗(n−1),n∗n]中
答案则为 n
当时比赛看数据范围不大,就直接暴力了
参考代码
// Problem: A. Find The Array
// Contest: Codeforces - Educational Codeforces Round 111 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1550/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
int main()
{
IOS;cin>>t;
while(t--){
cin>>n;
int sum=0,k=0;
for(int i=1;sum<n;i+=2){
sum+=i;
k++;
}
printf("%d\n",k);
}
}
B. Maximum Cost Deletion
思路点拨
题意
给定一个长度为n
的字符串s
,它只包含字符0
和1
。
您执行以下操作,直到字符串变空:选择一些连续的相同字符的子字符串,将其从字符串s
中删除,然后将剩余的两部分连接在一起。
例如,如果从字符串111110
中删除子字符串111
,您将得到字符串110
。当您删除长度为l
的子字符串时,您将得到a*l+b
点分数。
如果您必须将给定的字符串全部删除,您的任务是计算您总共可以获得的最大分数。
输入一个整数t
代表测试用例的数量
每个测试用例的第一行包含字符串s
的长度n
以及参数a
和b
第二行包含字符串s
。字符串s
仅由字符0
和1
组成
对于每个测试用例,输出您可以得分的最大点数
思路
我们不难发现,随着删除次数的增加,字符串s
总会被完全删除,所以
∑
a
∗
l
\sum a*l
∑a∗l其实就是a*n
所以关键就在b
上
当b>0
时,b
对结果的贡献是正向的,所以我们就尽量增加删除次数,让b
多做贡献,也就是一次只删除一个字符,最后结果就是
∑
a
∗
l
+
b
=
a
∗
n
+
b
∗
n
=
(
a
+
b
)
∗
n
\sum a*l+b = a*n+b*n =(a+b)*n
∑a∗l+b=a∗n+b∗n=(a+b)∗n
当b=0
时,对结果无影响
当b<0
时,对结果的贡献是反向的,所以我们就尽量减少删除次数,
这里我们用 num
记录相邻不同字符的个数,得出如下规律
num | 最少删除次数 |
---|---|
0 | 1 |
1 | 2 |
2 | 2 |
3 | 3 |
4 | 3 |
5 | 4 |
6 | 4 |
7 | 5 |
8 | 5 |
9 | 6 |
… | … |
num>0 | (num+1)/2+1 |
也就是当 n u m = 0 num=0 num=0,结果就是 ∑ a ∗ l + b = a ∗ n + b \sum a*l+b = a*n+b ∑a∗l+b=a∗n+b
当 n u m > 0 num>0 num>0,结果就是 ∑ a ∗ l + b = a ∗ n + ( ( n u m + 1 ) / 2 + 1 ) ∗ b \sum a*l+b = a*n+((num+1)/2+1)*b ∑a∗l+b=a∗n+((num+1)/2+1)∗b
参考代码
// Problem: B. Maximum Cost Deletion
// Contest: Codeforces - Educational Codeforces Round 111 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1550/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n,a,b;
string s;
int main()
{
IOS;cin>>t;
while(t--){
cin>>n>>a>>b>>s;
int num=0;
for(int i=1;s[i];i++)
if(s[i]!=s[i-1]) num++;
if(!num) num++;
else num=(num+1)/2+1;
if(b>=0) printf("%d",(a+b)*n);
else printf("%d",a*n+num*b);
puts("");
}
}
Codeforces Round #734 (Div. 3)
A. Polycarp and Coins
思路点拨
题意
你需要付款 n(n>0)
元
但你只有两个面值的硬币:1
元和2
元
你需要支付c1
个1
元硬币和c2
个2
元硬币使得支付总面值为n
元 即(c1+2*c2=n)
此外,你必须要使得|c1-c2|
尽可能小
给定多个n
,对于每个n
输出对应的c1
和c2
思路
当n%3==0
时,
c
1
=
c
2
=
n
/
3
c1=c2=n/3
c1=c2=n/3
当n%3!=0
时,
c
1
=
n
−
(
n
+
1
)
/
3
∗
2
c1=n-(n+1)/3*2
c1=n−(n+1)/3∗2,
c
2
=
(
n
+
1
)
/
3
c2=(n+1)/3
c2=(n+1)/3
我们发现第一种情况也满足第二种情况
n | c1(1) | c2(2) |
---|---|---|
1 | 1 | 0 |
2 | 0 | 1 |
3 | 1 | 1 |
4 | 2 | 1 |
5 | 1 | 2 |
6 | 2 | 2 |
7 | 3 | 2 |
8 | 2 | 3 |
9 | 3 | 3 |
10 | 4 | 3 |
参考代码
// Problem: A. Polycarp and Coins
// Contest: Codeforces - Codeforces Round #734 (Div. 3)
// URL: https://codeforces.com/contest/1551/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
int main()
{
cin>>t;
while(t--){
cin>>n;
printf("%d %d\n",n-(n+1)/3*2,(n+1)/3);
}
}
B1. Wonderful Coloring - 1
思路点拨
题意
Paul
和Mary
有一个最喜欢的字符串s
,它由小写字母组成。他们想用两种颜色的粉笔来画它:红色
和绿色
。如果满足以下条件,让我们将字符串的着色称为美妙
的:
- 字符串的每个字母要么
只涂上一种
颜色(红色或绿色),要么不涂
; - 涂上
相同
颜色的两个
字母各不相同
; - 涂
红色
字母的数量等于
涂绿色
字母的数量; - 在满足前三个条件的字符串的所有颜色中,该颜色的涂色字母
数量最多
。
输入t
个测试用例
每个测试用例由一个非空字符串s
组成,该字符串小写字母组成。字符串中的字符数不超过50
。
对于每个测试用例,输出将被涂成红色
并呈现美妙
色彩的字母数。
思路
根据题意我们可知:
由规则3
可得:如果该字母出现次数≥2的话,我们只选择其中两个字母分别涂上红色和绿色,剩余的不涂。如果该字母仅出现一次的话,我们也暂时先
选择不涂。
由规则4可得:我们可以在前面的基础上,对只出现过一次的字母(刚刚暂时先不涂的字母
)任意两两配对,分别涂上红色和绿色,这样可以使得涂色字母数量最多。
参考代码
// Problem: B1. Wonderful Coloring - 1
// Contest: Codeforces - Codeforces Round #734 (Div. 3)
// URL: https://codeforces.com/contest/1551/problem/B1
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t;
string s;
int main()
{
IOS;
cin>>t;
while(t--){
int a[30]={0};
int num1=0,num2=0;
cin>>s;
for(int i=0;s[i];i++)
a[s[i]-'a']++;
for(int i=0;i<26;i++)
if(a[i]==1) num1++;
else if(a[i]>=2) num2++;
cout<<num1/2+num2<<endl;
}
}
B2. Wonderful Coloring - 2(补)
思路点拨
题意
最近,Paul
和Mary
发现了一个新的最喜欢的整数序列 a[1],a[2],...,a[n]
。他们想用k
种颜色的粉笔来画它。如果满足以下条件,则序列的着色称为美妙
:
- 序列的每个元素要么用
k
种颜色之一绘制,要么不绘制; - 没有两个相同的值以相同颜色绘制;
k
种颜色中的每一种所绘制的元素数量必须相等;- 序列的着色元素总数是满足前三个条件的序列所有着色中的最大值。
序列a=[3,1,1,1,1,10,3,10,10,2]
和k=3
的美妙
着色示例。请注意,其中一个元素没有被绘制。
帮助Paul
和Mary
找出给定序列a
的美妙着色
。
输入t
个测试用例。
每个测试用例由两行组成。
第一个包含两个整数n
和k
(
1
≤
n
≤
2
E
5
,
1
≤
k
≤
n
)
(1≤n≤2E5, 1≤k≤n)
(1≤n≤2E5,1≤k≤n)分别是序列的长度
和颜色数
。
第二个包含 n 个整数a[1],a[2],...,a[n]
(
1
≤
a
i
≤
n
)
(1≤ai≤n)
(1≤ai≤n) 表示该序列。
保证所有测试用例的n
总和不超过2E5
。
输出t
行,每行都必须包含对相应测试用例的精彩着色的描述。
每个美妙的颜色都必须打印为由空格分隔的n
整数c[1],c[2],…,c[n]
(
0
≤
c
i
≤
k
)
(0≤ci≤k)
(0≤ci≤k)的序列,其中
ci=0
,如果第i
个元素没有被绘制;
ci>0
,如果第i
个元素以第ci
颜色绘制。
请记住,您需要最大化绘制元素的总数以获得美妙的色彩。如果有多种解决方案,请打印任何一种。
思路
我们现将原序列记录下来,再将原序列按照数值
排序,对于出现次数>k
的元素进行标记,遍历整个序列后统计出未被标记
的元素个数num
。
因为我们要保证各种颜色的个数统一,所以当
n
u
m
%
k
=
=
0
num\%k==0
num%k==0时,我们直接按照顺序进行填充即可。当
n
u
m
%
k
!
=
0
num\%k!=0
num%k!=0时,我们将前
n
u
m
%
k
num\%k
num%k个元素进行标记,然后将剩余元素按照顺序填充即可。
最后输出的时候记得先恢复原序列顺序哦!
参考代码
// Problem: B2. Wonderful Coloring - 2
// Contest: Codeforces - Codeforces Round #734 (Div. 3)
// URL: https://codeforces.com/contest/1551/problem/B2
// Memory Limit: 256 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n,k,p,num;
struct node{
int s,pos,num;
}a[200100];
bool cmp1(node a,node b){
return a.s<b.s;
}
bool cmp2(node a,node b){
return a.num<b.num;
}
int main()
{
IOS;
cin>>t;
while(t--){
cin>>n>>k;
p=1,num=n;
for(int i=0;i<n;i++){
cin>>a[i].s;
a[i].num=i;
}
sort(a,a+n,cmp1);
a[0].pos=1;
for(int i=0;i<n;i++){
if(i){
if(a[i].s==a[i-1].s) p++;
else p=1;
if(p>k) a[i].pos=-1,--num;
else a[i].pos=0;
}
//cout<<a[i].s<<" "<<a[i].pos<<endl;
}
for(int i=1;i<=num%k;i++)
a[i].pos=-1;
if(k-1) p=1;
else p=0;
for(int i=num%k+1;i<n;i++){
if(a[i].pos+1) a[i].pos=++p;
if(p==k) p=0;
}
sort(a,a+n,cmp2);
for(int i=0;i<n;i++){
if(i) cout<<" ";
if(a[i].pos+1) cout<<a[i].pos;
else cout<<"0";
}
cout<<endl;
}
}
C. Interesting Story(补)
思路点拨
题意
在每个测试样例中会给你一些字符串,每个字符串中只包含字母a-e
,你要在其中尽可能多地挑选并组合成一个新的字符串,使得得到的新字符串中某个字母出现的次数
比其余字母出现的次数总和
多,统计组成新字符串的旧字符串个数
思路
枚举每个字符串中a-e
各个字母的贡献,sort之后贪心,直到贡献非正。
参考代码
// Problem: C. Interesting Story
// Contest: Codeforces - Codeforces Round #734 (Div. 3)
// URL: https://codeforces.com/contest/1551/problem/C
// Memory Limit: 256 MB
// Time Limit: 4000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
struct node{
string k;
int pos[5];
}s[200100];
int p[5][200100];
int main()
{
cin>>t;
while(t--){
int a[5]={0};
cin>>n;
for(int i=0;i<n;i++){
cin>>s[i].k;
for(int j=0;s[i].k[j];j++)
a[s[i].k[j]-'a']++;
}
for(int k=0;k<5;k++){
char c=k+'a';
for(int i=0;i<n;i++){
int num=0;
for(int j=0;s[i].k[j];j++)
if(s[i].k[j]==c) num++;
s[i].pos[k]=num*2-s[i].k.length();
//计算第i个字符串中第k个字母的贡献
//这里把 num-(s[i].k.length()-num) 写成了 num*2-s[i].k.length();
}
}
for(int i=0;i<5;i++)
for(int j=0;j<n;j++)
p[i][j]=s[j].pos[i];
//p[i][j] 代表 第i个字母在第j个字符串中的贡献
//贪心
int maxx=0;
for(int i=0;i<5;i++){
sort(p[i],p[i]+n,greater<int>());
int num=0,sum=0;
for(int j=0;j<n;j++){
sum+=p[i][j];
if(sum>0) num++;
else break;
}
maxx=max(maxx,num);
}
cout<<maxx<<endl;
}
}
Codeforces Global Round 15
A. Subsequence Permutation
思路点拨
题意
给你一个长度为n
的字符串s
,你可以选择k
个字母保持不动
,改变剩余字母的排序,使得得到的新字符串是按字典序升序
,问k
是多少
思路
sort后遍历统计即可
参考代码
// Problem: A. Subsequence Permutation
// Contest: Codeforces - Codeforces Global Round 15
// URL: https://codeforces.com/contest/1552/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n,num;
string s;
int main()
{
cin>>t;
while(t--){
cin>>n>>s;
string k=s;
num=0;
sort(s.begin(),s.end());
for(int i=0;s[i];i++)
if(s[i]!=k[i]) num++;
printf("%d\n",num);
}
}
Codeforces Round #735 (Div. 2)
A. Cherry
思路点拨
题意
给你n
个数,下标记作[1,n]
,F(L,R)
定义为区间[L,R]
中最大的数和最小的数的乘积,让你找出最大的F(L,R)
是多少
思路
假如有这么一组数
a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
假如当我们选择L=2,R=6
时,假如最大值是a[5]
,最小值是a[3]
那F(2,6) = a[5] * a[3]
,那既然a[3]
是L=2,R=6
中最小的数,那我们应该选择L=4,R=6
,这样的话最大值还是a[5]
,但最小值一定会大于等于a[3]
,即F(4,6)≥F(2,6)
,以此类推我们发现当max和min不相邻的时候,就一定能够找出更优解
,所以只要枚举相邻两数乘积,输出最大值即可。
参考代码
// Problem: A. Cherry
// Contest: Codeforces - Codeforces Round #735 (Div. 2)
// URL: https://codeforces.com/contest/1554/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
ll t,n,maxx;
ll a[1000000];
int main()
{
IOS;cin>>t;
while(t--){
cin>>n>>a[0];
maxx=a[0];
for(ll i=1;i<n;i++){
cin>>a[i];
maxx=max(maxx,a[i]*a[i-1]);
}
cout<<maxx<<endl;
}
}
Educational Codeforces Round 112 (Rated for Div. 2)
A. PizzaForces(补)
思路点拨
题意
有小中大三种尺寸的披萨,小披萨
由6
片组成,中披萨
由8
片组成,大披萨
由10
片组成,制作时间分别是15
,20
,25
分钟。
每次有n
位朋友来参加聚会,你需要准备n
片披萨,请你求出制作至少包含n片
披萨所需的最小分钟数
。
思路
可以算出平均时间都是每2.5
分钟做好一片披萨,但当n
为奇数
时是没办法凑出来的,只能多做一片,特判一下n<6
的时候即可
参考代码
// Problem: A. PizzaForces
// Contest: Codeforces - Educational Codeforces Round 112 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1555/problem/A
// Memory Limit: 256 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
ll t,n;
int main()
{
cin>>t;
while(t--){
cin>>n;
if(n&1) n++;
if(n<6) n=6;
cout<<n*2+n/2<<endl;
}
}
B. Two Tables(补)
思路点拨
题意
有一个与轴对齐的矩形房间,宽度为W
,高度为H
左下角在(0,0)
,右上角在(W,H)
这个房间里有一张长方形的桌子,桌子的侧面与墙壁平行
左下角位于(x1,y1)
,右上角位于(x2,y2)
。
您希望在此房间中放置另一张矩形桌子,宽度为w
,高度为h
桌子的宽度与房间的宽度平行。
问题是有时没有足够的空间来放置第二个桌子而不与第一个桌子相交(尽管桌子接触没有问题)
您不能旋转任何桌子,但可以在房间内移动第一张桌子。
为了给第二张桌子腾出足够的空间,移动第一张桌子的最小距离
是多少?
思路
计算两个桌子的总宽和总高,与房间的宽高比较,看看能否放得下
放得下的话则验证不移动能否放得下
否则左右能放则取最小值maxx1
,上下能放则取最小值maxx2
,答案即min(maxx1,maxx2)
参考代码
// Problem: B. Two Tables
// Contest: Codeforces - Educational Codeforces Round 112 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1555/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t;
int w,h,x1,y1,x2,y2,ww,hh;
int main()
{
cin>>t;
while(t--){
cin>>w>>h>>x1>>y1>>x2>>y2>>ww>>hh;
if(ww-x1+x2>w&&hh-y1+y2>h) puts("-1");
else if(y1>=hh||x1>=ww||w-x2>=ww||h-y2>=hh) puts("0.000000000");
else{
double maxx1=INT_MAX,maxx2=INT_MAX;
if(ww-x1+x2<=w) maxx1=min(abs(x1-ww),abs(x2-(w-ww)));
if(hh-y1+y2<=h) maxx2=min(abs(y1-hh),abs(y2-(h-hh)));
printf("%.9lf\n",min(maxx1,maxx2));
}
}
}
C. Coin Rows(补)
思路点拨
题意
该矩阵由2
行,m
列组成
第i
行第j
列的单元格中包含a[i][j
]硬币
起初A和B都在(1,1)
处,每次移动,他们可以向右
或向下
走,直到走到(2,m)
处
A
先走,B
后走
游戏的分数是B
收集的硬币总数。
A
想把分数降到最低,B
想把分数尽可能提高,他们都绝对聪明
思路
因为两人绝对聪明,A
只能往下走一次,当A
从第k
格往下走的时候,B
的分数就是max(
∑
s
=
k
+
1
n
a
[
1
]
[
s
]
∑^n_{s=k+1}a[1][s]
∑s=k+1na[1][s],
∑
s
=
1
k
−
1
a
[
1
]
[
s
]
∑^{k-1}_{s=1}a[1][s]
∑s=1k−1a[1][s]),所以预处理一下遍历即可。
参考代码
// Problem: C. Coin Rows
// Contest: Codeforces - Educational Codeforces Round 112 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1555/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
int a[3][100100];
int main()
{
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=2;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
if(n==1){
puts("0");
continue;
}
for(int i=n-1;i>=1;i--)
a[1][i]+=a[1][i+1];
for(int i=2;i<=n;i++)
a[2][i]+=a[2][i-1];
int minn=INT_MAX;a[1][n+1]=0,a[2][0]=0;
for(int i=1;i<=n;i++)
minn=min(minn,max(a[1][i+1],a[2][i-1]));
cout<<minn<<endl;
}
}
Codeforces Round #736 (Div. 2)
A. Gregor and Cryptography
思路点拨
题意
给你素数P
。两个整数a
和b
使得
P
%
a
=
P
%
b
P\%a=P\%b
P%a=P%b
思路
P
是素数,肯定是奇数,所以
P
%
2
=
1
P\%2=1
P%2=1,要使得
P
%
b
=
1
P\%b=1
P%b=1,很显然
b
=
P
−
1
b=P-1
b=P−1
参考代码
// Problem: A. Gregor and Cryptography
// Contest: Codeforces - Codeforces Round #736 (Div. 2)
// URL: https://codeforces.com/contest/1549/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
int main(){
cin>>t;
while(t--){
cin>>n;
cout<<2<<" "<<n-1<<endl;
}
}
B. Gregor and the Pawn Game
思路点拨
题意
有一个大小为n*n
的棋盘。
G
在第n
排有一些棋子。第1
排有敌人的棋子
在一个回合中,G
移动了他的一个棋子
如果那颗棋子上方没有棋子的话,G
可以向上移动棋子
(
从
[
i
,
j
]
到
[
i
−
1
,
j
]
)
(从[i,j]到[i-1,j])
(从[i,j]到[i−1,j])
否则,当且仅当该方格中有敌方棋子时,G
的棋子可以沿对角线向左上或右上移动,
(
从
[
i
,
j
]
到
[
i
−
1
,
j
−
1
]
或
[
i
−
1
,
j
+
1
]
)
(从[i,j]到[i−1,j−1]或[i−1,j+1])
(从[i,j]到[i−1,j−1]或[i−1,j+1])。移动后该位置上敌人的棋子将被移除。
G
想知道他能到达第一排的最大棋子数是多少?
请注意,在这个游戏中只有G
的棋子在移动,而敌方的棋子从不移动
此外,当G
的棋子到达第一排时,它就不能再移动了。
思路
模拟即可
参考代码
// Problem: B. Gregor and the Pawn Game
// Contest: Codeforces - Codeforces Round #736 (Div. 2)
// URL: https://codeforces.com/contest/1549/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
int a[2][200100];
int main()
{
cin>>t;
while(t--){
scanf("%d",&n);getchar();
for(int i=0;i<=1;i++){
for(int j=0;j<n;j++)
a[i][j]=getchar()-'0';
getchar();
}
int num=0;
for(int i=0;i<n;i++){
if(a[1][i]){
if(!a[0][i]) num++;
else if(i-1>=0&&a[0][i-1]) a[0][i-1]=0,num++;
else if(i+1<n&&a[0][i+1]) a[0][i+1]=0,num++;
}
}
printf("%d\n",num);
}
}
Codeforces Round #737 (Div. 2)
A. Ezzat and Two Subsequences
思路点拨
题意
给你一组数,请你把它们成两组,计算每组的平均数,使得两组的平均数的和最大
思路
最大的一个数单独一组,剩下的数一组
最大的数除以1
,其他的除以(n-1)
参考代码
// Problem: A. Ezzat and Two Subsequences
// Contest: Codeforces - Codeforces Round #737 (Div. 2)
// URL: https://codeforces.com/contest/1557/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
/
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
int a[100100];
int main()
{
cin>>t;
while(t--){
double sum=0;int maxx=INT_MIN;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
maxx=max(maxx,a[i]);
sum+=a[i];
}
sum-=maxx;
printf("%.10lf\n",sum/(n-1)+maxx);
}
}
B. 离散化的题待补(补)
思路点拨
题意
思路
参考代码
Codeforces Round #738 (Div. 2)
A. Mocha and Math
思路点拨
题意
有一个长度为n
的数组a
,在每次操作中,她可以选择任意的区间[L,R]
,用a[L+i]&a[R−i]
替换a[L+i]
,其中0≤i≤R−L
,&
表示按位与运算。 此操作可以执行任意次,能否使操作后的数组中的最大值最小,求操作后数组中的最大值是多少?
思路
根据按位与的性质,有0
出0
,全1
出1
,两个数a
和b
按位与之后的结果是c
,那么c≤max(a,b)
,那么直接遍历异或即可
参考代码
// Problem: A. Mocha and Math
// Contest: Codeforces - Codeforces Round #738 (Div. 2)
// URL: https://codeforces.com/contest/1559/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n;
int a[110];
int main()
{
cin>>t;
while(t--){
cin>>n>>a[0];
for(int i=1;i<n;i++){
cin>>a[i];
a[0]&=a[i];
}
cout<<a[0]<<endl;
}
}
B. Mocha and Red and Blue
思路点拨
题意
给你一个由B
,R
,?
构成的字符串,B
代表蓝色,R
代表红色,?
代表空白。
我们把相邻的具有相同的颜色的方块称作不完美
,例如BB
,RR
。
现在你可以选择在空白处涂上蓝色
或红色
,使得最后得到的字符串的不完美
的个数最少
,输出涂色后的字符串
思路
首先统计字符串中?
的个数
如果全是?
的话则先把第一个随意涂色
特判字符串长度为1
的时候,把?
随意涂色之后输出
从头至尾遍历,对于形如B?
或R?
,涂色成BR
或RB
从尾至头遍历,对于形如?B
或?R
,涂色成RB
或BR
参考代码
// Problem: B. Mocha and Red and Blue
// Contest: Codeforces - Codeforces Round #738 (Div. 2)
// URL: https://codeforces.com/contest/1559/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n,len,num;
string s;
int main()
{
cin>>t;
while(t--){
cin>>len>>s;
num=0;
for(int i=0;s[i];i++)
num+=s[i]!='?';
if(!num) s[0]='B';
if(s.length()==1&&s[0]=='?') cout<<'B'<<endl;
else{
for(int i=0;s[i];i++)
if(!i) continue;
else if(s[i]=='?'&&s[i-1]!='?') s[i]=s[i-1]^('B'^'R');
for(int i=s.length()-1;i>=0;i--)
if(i==s.length()-1) continue;
else if(s[i]=='?'&&s[i+1]!='?') s[i]=s[i+1]^('B'^'R');
cout<<s<<endl;
}
}
}
C. Mocha and Hiking(补)
思路点拨
题意
给你一个数字n
,表示有n+1
个村庄和2n-1
条路
对于[1,n-1]的村庄都有一条有向路通向下一个村庄
下一行有一个由n
个数字组成的数组a
a[i]=0
时,表示村庄i
到村庄n+1
有一条有向路
a[i]=1
时,表示村庄n+1
到村庄i
有一条有向路
请你找出一条路径,使得你能从任意起点开始走完所有村庄,找不到输出-1
思路
首先判断从n
到n+1
是否有路,有路则直接输出[1,n+1]
其次判断从n+1
到1
是否有路,有路则先输出n+1
,再输出[1,n]
最后判断是否有形如a[i]==0&&a[i+1]==1
,有的话则表示能从i
走到n+1
后还能回到i+1
,则输出[1,i],n+1,[i+1,n]
不满足上述要求则无解
参考代码
// Problem: C. Mocha and Hiking
// Contest: Codeforces - Codeforces Round #738 (Div. 2)
// URL: https://codeforces.com/contest/1559/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n,a[10100];
int main()
{
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
if(!a[n]){
for(int i=1;i<=n;i++)
cout<<i<<" ";
cout<<n+1<<endl;
}
else if(a[1]){
cout<<n+1<<" ";
for(int i=1;i<n;i++)
cout<<i<<" ";
cout<<n<<endl;
}
else{
bool f=true;
for(int i=1;i<n&&f;i++)
if(!a[i]&&a[i+1]){
cout<<"1";
for(int j=2;j<=i;j++)
cout<<" "<<j;
cout<<" "<<n+1;
for(int j=i+1;j<=n;j++)
cout<<" "<<j;
cout<<endl;
f=false;
}
if(f) puts("-1");
}
}
}
Codeforces Round #739 (Div. 3)
A. Dislike of Threes
思路点拨
题意
有一个数组,从1
开始,不包括以3
结尾的数字和3
的倍数
输入一个数k
,输出数组中第k
个数字
思路
预处理打表输出即可
参考代码
// Problem: A. Dislike of Threes
// Contest: Codeforces - Codeforces Round #739 (Div. 3)
// URL: https://codeforces.com/contest/1560/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
int t,n,pos;
int a[1100];
int main()
{
for(int i=0;pos<1100;i++)
if(i%3==0||i%10==3) continue;
else a[pos++]=i;
cin>>t;
while(t--){
cin>>n;
cout<<a[n-1]<<endl;
}
}
B. Who’s Opposite?
思路点拨
题意
有若干个人站成一圈。人们均匀地站在圆圈里。它们从编号为1
的人开始顺时针编号。每个人都通过圆圈的中心看对面的人。给你三个数a
,b
,c
,即a
对面是b
,求c
的对面是谁?
思路
规律1:我们假设a>b
,那么对立着的两人的差是固定不变的,都是a-b
。所以跟c
对立的编号是c+(a-b)
或c-(a-b)
规律2:最小的编号是1
,最大的编号是(a-b)*2
接下来只要判断这两个编号a
,b
是否合法
并且这三个不重复
即可
参考代码
// Problem: B. Who's Opposite?
// Contest: Codeforces - Codeforces Round #739 (Div. 3)
// URL: https://codeforces.com/contest/1560/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
LL t,a,b,c,n;
int main()
{
cin>>t;
while(t--){
cin>>a>>b>>c;
if(a<b) swap(a,b);
LL eps=a-b,maxx=(a-b)*2;
LL c1=c+eps,c2=c-eps;
if(c>maxx||maxx<a||maxx<b) puts("-1");
else if(c1<=maxx&&c1!=a&&c1!=b) cout<<c1<<endl;
else if(c2>0&&c2!=a&&c2!=b) cout<<c2<<endl;
else puts("-1");
}
}
C. Infinity Table
思路点拨
题意
根据题目中的图示填数,给你一个数n,输出在第几行第几列
思路
第i
行第i
列上的数字是i*(i-1)+1
第一列的数字都是平方数,所以平方数都在第sqrt(n)
行,第1
列
其次判断n
是否在第sqrt(n)+1
行上,即n是否在[ (sqrt(n)+1)*sqrt(n)+1 , (sqrt(n)+1 )*(sqrt(n)+1) ]
中
否则n就一定在第sqrt(n)+1
列上,再根据(sqrt(n)+1)*sqrt(n)+1
的差来判断在第几行上
参考代码
// Problem: C. Infinity Table
// Contest: Codeforces - Codeforces Round #739 (Div. 3)
// URL: https://codeforces.com/contest/1560/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
LL t,n;
int main()
{
cin>>t;
while(t--){
cin>>n;
LL xx,yy,kk,tp=sqrt(n);
if(n==tp*tp) xx=tp,yy=1;
else {
xx=tp+1,yy=1,kk=(tp+1)*(tp+1);
if(n>=(kk-xx+1)) yy=kk-n+1;
else{
yy=xx;
kk=kk-xx+1;
xx=xx-(kk-n);
}
}
cout<<xx<<" "<<yy<<endl;
}
}