前言
额,之前写的组队赛总结有人抱怨题目都是英文看不懂,,好吧那这次就用中文,原题我会放在题目下方想看的可以戳进去。本轮大部分用的都是俄罗斯的题目。毛子很刚啊出的题很多都是纯数学,物理的题目再加上英文简直让人抓狂。。。
个人赛
0.卡片
题目链接:https://codeforces.com/problemset/problem/1220/A
题目大意:给一串字符,问能凑出的最大数字。
思路:先凑一后凑0这是个签到题简单没必要多讲,有兴趣的可以看看。
#include<bits/stdc++.h>
using namespace std;
int main(){
map<char,int> mp;
int n;
scanf("%d",&n);
getchar();
char s;
for(int i=0;i<n;i++){
scanf("%c",&s);
if(s=='z') mp['z']+=1;
else if(s=='e') mp['e']+=1;
else if(s=='r') mp['r']+=1;
else if(s=='o') mp['o']+=1;
else if(s=='n') mp['n']+=1;
}
//printf("%d %d %d %d %d",mp['z'],mp['e'],mp['r'],mp['o'],mp['n']);
int ans1 = min(mp['o'],mp['n']);
ans1 = min(ans1,mp['e']);
mp['o']-=ans1;
mp['n']-=ans1;
mp['e']-=ans1;
int ans2 = min(mp['z'],mp['e']);
ans2 = min(ans2,mp['r']);
ans2 = min(ans2,mp['o']);
int jh=0;
for(int i=0;i<ans1;i++){
if(jh==1)printf(" 1");
else printf("1");
jh=1;
}
for(int i=0;i<ans2;i++){
if(jh==1) printf(" 0");
else printf("0");
jh=1;
}
}
1.乘法表
题目链接:https://codeforces.com/gym/101173/attachments
题目大意:Sasha生日的时候妈妈给她买了个类似于乘法表的玩具,在这个表中有n个未知数,索引分别从1~n。在表的i行j列上的数字为n个未知数中第i个*第j个,当i=j时为0。现在给你这个表。请你求出这n个数字。测试样例如下
Input
5
0 4 6 2 4
4 0 6 2 4
6 6 0 3 6
2 2 3 0 2
4 4 6 2 0
Output
2 2 3 1 2
Input
3
0 99990000 99970002
99990000 0 99980000
99970002 99980000 0
Output
9999 10000 9998
思路:其实有点数学思维都可以根据题目发现,在表中a[1][2]*a[1][3]/a[2][3]开根号就能求出n1,之后遍历第一列把n2~nn分别求出来即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[1005][1005];
ll b[1005];
int main(){
int n;
memset(b,0,sizeof(b));
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&a[i][j]);
}
}
b[1]=sqrt(a[1][2]*a[1][3]/a[2][3]);
for(int i=2;i<=n;i++){
b[i]=a[1][i]/b[1];
}
for(int i=1;i<=n;i++){
if(i==1) printf("%lld",b[i]);
else printf(" %lld",b[i]);
}
}
2.敲击!
题目链接:https://codeforces.com/gym/101173/attachments
题目大意:一个正在从手术中康复的人研究起了一种钥匙(果然人闲就是事多。。)这把钥匙是一串由n3个0,1字符组成的字符串。他的价值是
相邻两字符不一样的个数+1,例如"000"的价值是1,“011010100"的价值是7。现在他可以通过敲击来篡改这个串上两个相邻的数字,比如"000"中敲击第一个0会变成"110”。现在他只能敲击最多n下,如何敲击才能使价值不小于2n呢?
测试样例:对于每个样例首先输出敲击次数,然后输出敲击位置。字符串最长不会超过300000.
input
000000000
output
3
2 5 6
input
111001000111
output
2
3 9
input
010101
output
0
思路:根据题意字符串肯定能按照每三个一份分成n份,那么只需要每份的最低贡献值为2即可。根据每份的上一份最后一个来讨论,具体可看代码。
#include<bits/stdc++.h>
using namespace std;
string s;
//所有可能情况
string situation[8]={"000","001","010","011","100","101","110","111"};
int ans[100005];
int jh=1;
//根据每份上一份的最后一个数字来决定这一份的处理
void Do0(int x){
string s_=s.substr(x,3);
for(int i=0;i<=7;i++){
if(s_==situation[i]){
if(i==0||i==3){
ans[0]+=1;
ans[jh++]=x+1;
}else if(i==1||i==7){
ans[0]+=1;
ans[jh++]=x+2;
s[x+2]='0';
}
}
}
}
void Do1(int x){
string s_=s.substr(x,3);
for(int i=0;i<=7;i++){
if(s_==situation[i]){
if(i==4||i==7){
ans[0]+=1;
ans[jh++]=x+1;
}else if(i==0||i==6){
ans[0]+=1;
ans[jh++]=x+2;
s[x+2]='1';
}
}
}
}
int main(){
cin>>s;
memset(ans,0,sizeof(ans));
int n=s.length()/3;
for(int i=0;i+2<s.length();i+=3){
if(ans[0]>=2*n) break;
//第一份单独处理,只要第一份的贡献>=1即可,因为题目中有一个+1.
//这个卡了我好久。。
if(i==0){
string s_ = s.substr(0,3);
for(int i=0;i<8;i++){
if(situation[i]==s_){
if(i==0||i==7){
ans[0]+=1;
ans[jh++]=2;
if(i==0) s[2]='1';
if(i==7) s[2]='0';
}
break;
}
}
}
else{
if(s[i-1]=='1'){
Do1(i);
}else if(s[i-1]=='0'){
Do0(i);
}
}
}
for(int i=0;i<jh;i++){
if(i==0){
printf("%d\n",ans[0]);
}else{
if(i==1){
printf("%d",ans[i]);
}else{
printf(" %d",ans[i]);
}
}
}
}
3.哈密顿绕行世界问题
一个规则的实心十二面体,它的 20个顶点标出世界著名的20个城市,你从一个城市出发经过每个城市刚好一次后回到出发的城市。
这个就是中文题!而且这就是题目!有什么要求你细品。
Input
前20行的第i行有3个数,表示与第i个城市相邻的3个城市.第20行以后每行有1个数m,m<=20,m>=1.m=0退出.
Output
输出从第m个城市出发经过每个城市1次又回到m的所有路线,如有多条路线,按字典序输出,每行1条路线.每行首先输出是第几条路线.然后个一个: 后列出经过的城市.
Sample output
Sample Input
2 5 20
1 3 12
2 4 10
3 5 8
1 4 6
5 7 19
6 8 17
4 7 9
8 10 16
3 9 11
10 12 15
2 11 13
12 14 20
13 15 18
11 14 16
9 15 17
7 16 18
14 17 19
6 18 20
1 13 19
5
0
Sample Output
1: 5 1 2 3 4 8 7 17 18 14 15 16 9 10 11 12 13 20 19 6 5
2: 5 1 2 3 4 8 9 10 11 12 13 20 19 18 14 15 16 17 7 6 5
3: 5 1 2 3 10 9 16 17 18 14 15 11 12 13 20 19 6 7 8 4 5
4: 5 1 2 3 10 11 12 13 20 19 6 7 17 18 14 15 16 9 8 4 5
5: 5 1 2 12 11 10 3 4 8 9 16 15 14 13 20 19 18 17 7 6 5
6: 5 1 2 12 11 15 14 13 20 19 18 17 16 9 10 3 4 8 7 6 5
7: 5 1 2 12 11 15 16 9 10 3 4 8 7 17 18 14 13 20 19 6 5
8: 5 1 2 12 11 15 16 17 18 14 13 20 19 6 7 8 9 10 3 4 5
9: 5 1 2 12 13 20 19 6 7 8 9 16 17 18 14 15 11 10 3 4 5
10: 5 1 2 12 13 20 19 18 14 15 11 10 3 4 8 9 16 17 7 6 5
11: 5 1 20 13 12 2 3 4 8 7 17 16 9 10 11 15 14 18 19 6 5
12: 5 1 20 13 12 2 3 10 11 15 14 18 19 6 7 17 16 9 8 4 5
13: 5 1 20 13 14 15 11 12 2 3 10 9 16 17 18 19 6 7 8 4 5
14: 5 1 20 13 14 15 16 9 10 11 12 2 3 4 8 7 17 18 19 6 5
15: 5 1 20 13 14 15 16 17 18 19 6 7 8 9 10 11 12 2 3 4 5
16: 5 1 20 13 14 18 19 6 7 17 16 15 11 12 2 3 10 9 8 4 5
17: 5 1 20 19 6 7 8 9 10 11 15 16 17 18 14 13 12 2 3 4 5
18: 5 1 20 19 6 7 17 18 14 13 12 2 3 10 11 15 16 9 8 4 5
19: 5 1 20 19 18 14 13 12 2 3 4 8 9 10 11 15 16 17 7 6 5
20: 5 1 20 19 18 17 16 9 10 11 15 14 13 12 2 3 4 8 7 6 5
21: 5 4 3 2 1 20 13 12 11 10 9 8 7 17 16 15 14 18 19 6 5
22: 5 4 3 2 1 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5
23: 5 4 3 2 12 11 10 9 8 7 6 19 18 17 16 15 14 13 20 1 5
24: 5 4 3 2 12 13 14 18 17 16 15 11 10 9 8 7 6 19 20 1 5
25: 5 4 3 10 9 8 7 6 19 20 13 14 18 17 16 15 11 12 2 1 5
26: 5 4 3 10 9 8 7 17 16 15 11 12 2 1 20 13 14 18 19 6 5
27: 5 4 3 10 11 12 2 1 20 13 14 15 16 9 8 7 17 18 19 6 5
28: 5 4 3 10 11 15 14 13 12 2 1 20 19 18 17 16 9 8 7 6 5
29: 5 4 3 10 11 15 14 18 17 16 9 8 7 6 19 20 13 12 2 1 5
30: 5 4 3 10 11 15 16 9 8 7 17 18 14 13 12 2 1 20 19 6 5
31: 5 4 8 7 6 19 18 17 16 9 10 3 2 12 11 15 14 13 20 1 5
32: 5 4 8 7 6 19 20 13 12 11 15 14 18 17 16 9 10 3 2 1 5
33: 5 4 8 7 17 16 9 10 3 2 1 20 13 12 11 15 14 18 19 6 5
34: 5 4 8 7 17 18 14 13 12 11 15 16 9 10 3 2 1 20 19 6 5
35: 5 4 8 9 10 3 2 1 20 19 18 14 13 12 11 15 16 17 7 6 5
36: 5 4 8 9 10 3 2 12 11 15 16 17 7 6 19 18 14 13 20 1 5
37: 5 4 8 9 16 15 11 10 3 2 12 13 14 18 17 7 6 19 20 1 5
38: 5 4 8 9 16 15 14 13 12 11 10 3 2 1 20 19 18 17 7 6 5
39: 5 4 8 9 16 15 14 18 17 7 6 19 20 13 12 11 10 3 2 1 5
40: 5 4 8 9 16 17 7 6 19 18 14 15 11 10 3 2 12 13 20 1 5
41: 5 6 7 8 4 3 2 12 13 14 15 11 10 9 16 17 18 19 20 1 5
42: 5 6 7 8 4 3 10 9 16 17 18 19 20 13 14 15 11 12 2 1 5
43: 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5
44: 5 6 7 8 9 16 17 18 19 20 1 2 12 13 14 15 11 10 3 4 5
45: 5 6 7 17 16 9 8 4 3 10 11 15 14 18 19 20 13 12 2 1 5
46: 5 6 7 17 16 15 11 10 9 8 4 3 2 12 13 14 18 19 20 1 5
47: 5 6 7 17 16 15 11 12 13 14 18 19 20 1 2 3 10 9 8 4 5
48: 5 6 7 17 16 15 14 18 19 20 13 12 11 10 9 8 4 3 2 1 5
49: 5 6 7 17 18 19 20 1 2 3 10 11 12 13 14 15 16 9 8 4 5
50: 5 6 7 17 18 19 20 13 14 15 16 9 8 4 3 10 11 12 2 1 5
51: 5 6 19 18 14 13 20 1 2 12 11 15 16 17 7 8 9 10 3 4 5
52: 5 6 19 18 14 15 11 10 9 16 17 7 8 4 3 2 12 13 20 1 5
53: 5 6 19 18 14 15 11 12 13 20 1 2 3 10 9 16 17 7 8 4 5
54: 5 6 19 18 14 15 16 17 7 8 9 10 11 12 13 20 1 2 3 4 5
55: 5 6 19 18 17 7 8 4 3 2 12 11 10 9 16 15 14 13 20 1 5
56: 5 6 19 18 17 7 8 9 16 15 14 13 20 1 2 12 11 10 3 4 5
57: 5 6 19 20 1 2 3 10 9 16 15 11 12 13 14 18 17 7 8 4 5
58: 5 6 19 20 1 2 12 13 14 18 17 7 8 9 16 15 11 10 3 4 5
59: 5 6 19 20 13 12 11 10 9 16 15 14 18 17 7 8 4 3 2 1 5
60: 5 6 19 20 13 14 18 17 7 8 4 3 10 9 16 15 11 12 2 1 5
思路:经典名字经典题型,每条可行的路都走一边走完以后再判断可不可行可行输出否则回溯,深度优先搜索,与后边介绍的广度优先搜索不一样的地方在于,深度优先搜索需要一条路走到黑,等走完了再看看行不行,不行回溯再选一条。嗯就是有后悔药吃的人生,管你怎么样先走再说。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
//dfs算法
bool map[21][21];//用于储存地图
bool point[21];//统计到过的点
int pos[21];//存储依次经过的点,用于输出;
int m;//起点
int num;//统计经过节点个数
int t;//解的个数
//检查是否构成回路,即最后一个位置与终点相连
int check(int m){
if(map[pos[num]][m]==0){
return 0;
}
return 1;
}
void dfs(int step){
if(num>=20){
if(check(m)){
printf("%d: %d",++t,m);
for(int i=2;i<=num;i++){
printf(" %d",pos[i]);
}
printf(" %d\n",m);
}
return;
}
for(int i=1;i<=20;i++){
if(map[step][i]&&!point[i]){
num++;
pos[num]=i;//标记
point[i]=true;
dfs(i);//继续走
point[i]=!true;//回溯
num--;
}
}
}
int main(){
memset(map,0,sizeof(map));
for(int i=1;i<=20;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
//打通地图
map[i][x] = true;
map[x][i] = true;
map[i][y] = true;
map[y][i] = true;
map[i][z] = true;
map[z][i] = true;
}
while(true){
scanf("%d",&m);
if(m==0) break;
else {
t=0;
num=1;
memset(point,0,sizeof(point));
point[m]=true;
dfs(m);
pos[1]=m;
}
}
}
4.考拉与灯
题目链接:https://codeforces.com/problemset/problem/1209/B
题目大意:一个叫考拉的发现有一排灯,每个灯都有自己的开关周期。问在一段时间内最多同时亮几盏灯。
测试样例:
Input
3
101
3 3
3 2
3 1
Output
2
Input
4
1111
3 4
5 2
3 1
3 2
Output
4
Input
6
011100
5 3
5 5
2 4
3 5
4 2
1 5
Output
6
思路:没啥好想的,直接对于每一秒来暴力找最大亮着的灯。数据给不大不会超时的。。签到题。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct nd{
int ai;
int bi;
}nds[105];
int main(){
int n;
scanf("%d",&n);
string s;
cin>>s;
int maxans=0;
int maxchange=0;
for(int i=0;i<n;i++){
scanf("%d%d",&nds[i].ai,&nds[i].bi);
if(i==0) maxchange=nds[i].ai+nds[i].bi;
else{
maxchange=max(maxchange,nds[i].ai+nds[i].bi);
}
if(s[i]=='1') maxans+=1;
}
for(int i=0;i<=300;i++){
int ans=0;
for(int j=0;j<n;j++){
for(int k=0;nds[j].bi+(k*nds[j].ai)<=i;k++){
if(nds[j].bi+(k*nds[j].ai)==i){
if(s[j]=='1'){
s[j]='0';
}else{
s[j]='1';
}
break;
}
}
if(s[j]=='1') ans+=1;
}
maxans=max(maxans,ans);
//cout<<ans<<' '<<s<<endl;
}
printf("%d\n",maxans);
}
5.数字分组
题目链接:https://codeforces.com/problemset/problem/1209/C
题目大意:给定一行数字,你可以对每个数字进行标记(‘1’或’2’)要求:将所有标号为1的数字提到2前使得整行数字单调递增。标号为1的操作尽可能的少,输出标记好的数字,若不可能输出’-’。
测试样例
Input
5
12
040425524644
1
0
9
123456789
2
98
3
987
Output
121212211211
1
222222222
21
-
思路:枚举可能边界,大于的标2,小的标1,如果相等则看情况讨论
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int f[200005],s[200005];
int fi=0,se=0;
int main(){
int n;
scanf("%d",&n);
while(n--){
int len;
int a[10];
memset(a,0,sizeof(a));
scanf("%d",&len);
string ss;
cin>>ss;
map<int,int> mp;
int yes=0;
for(int i=0;i<len;i++){
if(yes) break;
if(a[ss[i]-'0']==0){
a[ss[i]-'0']=1;
fi=0;se=0;
int jh=0;
for(int j=0;j<len;j++){
//printf("%c %c\n",s[i],s[j]);
if(ss[i]==ss[j]){
//if(ss[i]=='4') cout<<"deng"<<endl;
if(jh==1){
f[++fi]=ss[j]-'0';
if(f[fi]>=f[fi-1]){
mp[j]=1;
}else{
break;
}
}else{
s[++se]=ss[j]-'0';
if(s[se]>=s[se-1]){
mp[j]=2;
}else{
break;
}
}
// if(ss[i]=='4') cout<<"deng"<<endl;
}
else if(ss[j]<ss[i]){
//cout<<"xiao"<<endl;
f[++fi]=ss[j]-'0';
//if(ss[i]=='4') printf("%d %d",f[fi],f[fi-1]);
if(f[fi]>=f[fi-1]){
mp[j]=1;
}else{
break;
}
}
else if(ss[j]>ss[i]){
//if(ss[i]=='4') cout<<"da"<<endl;
s[++se]=ss[j]-'0';
if(s[se]>=s[se-1]){
mp[j]=2;
}else{
break;
}
jh=1;
}
if(j==len-1){
yes=1;
}
}
}else{
continue;
}
}
if(yes){
for(int i=0;i<len;i++){
printf("%d",mp[i]);
}
printf("\n");
}else{
printf("-\n");
}
}
}
/*
1
12
040425524644
*/
6.跳跳蛙
题目链接:http://poj.org/problem?id=2253
题目大意:首先给出一个定义:一个点到另一个点(可借助中间点)最远的跳跃距离为青蛙距离例如下图
若直接从A到B则青蛙距离为5,若借C来到B则青蛙距离为4.
给定n个点,求从起点到终点的最小青蛙距离。
测试样例:
Sample Input
2
0 0
3 4
3
17 4
19 4
18 5
0
Sample Output
Scenario #1
Frog Distance = 5.000
Scenario #2
Frog Distance = 1.414
思路:类似于带权图求最短路,弗洛伊德算法orDijkstra算法。离散数学刚刚学过,写起来并不难。先把每个点到终点的距离记录,再用中间变量k遍历每个可能的跳板。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 9999999;
int jl(int x1,int y1,int x2,int y2){
return (x2-x1)*(x2-x1)+(y1-y2)*(y1-y2);
}
int main(){
int n;
int x[205],y[205];
int juli[205][205];
int flag=1;
while(scanf("%d",&n),n!=0){//Dijkstra算法初始化
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) juli[i][j]=0;
else{
juli[i][j] = maxn;
}
}
}
for(int i=1;i<=n;i++){
scanf("%d%d",&x[i],&y[i]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
juli[i][j] = juli[j][i] = jl(x[i],y[i],x[j],y[j]);
}
}
int a;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
//寻找可能缩短青蛙距离的跳板
if(juli[i][k]>juli[k][j]){
a = juli[i][k];
}else{
a = juli[k][j];
}
if(a<juli[i][j]){
juli[i][j] = a;
}
}
printf("Scenario #%d\n",flag++);
printf("Frog Distance = %.3lf\n\n",sqrt((double)juli[1][2]));
}
return 0;
}
7.地牢之王
题目链接:http://poj.org/problem?id=2251
题目大意:你被困在了一个3d的地牢里了,快想办法逃出去!
1.每次移动一格
2.不能穿墙
3.输出最短路径,走不出去输出“困住了!”
测试样例:
Sample Input
3 4 5
S....
.###.
.##..
###.#
#####
#####
##.##
##...
#####
#####
#.###
####E
1 3 3
S##
#E#
###
0 0 0
Sample Output
Escaped in 11 minute(s).
Trapped!
思路:额有点另类的最短路问题,用数组存起来把他当成2d的用广度优先搜索直接上!
广度优先搜索:暴力的美称,举个例子你即将出门但是钥匙丢了,那么你怎么去找你的钥匙呢,1.先把客厅搜一圈2.再把客厅周围的房间搜一圈3.一圈一圈直到搜完客厅。嗯。。发现钥匙在口袋里(皮一下)总之大概就是这个步骤-先把最近的找一圈,在逐层往下,这样先找到的出口就是最短的路径了。
#include<cstdio>
#include<string.h>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
int x_end,y_end,z_end;
int x_begin,y_begin,z_begin;
int a,b,c;
typedef struct man{
int x,y,z;
int step;
}man;
int go[6][3]={{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1},};//六个步骤,分别代表六个方向。
bool is[35][35][35];
char mp[35][35][35];
bool check(int x,int y,int z){
if(x<0||x>=a||y<0||y>=b||z<0||z>=c) return true;//是否越界
else if(is[x][y][z]) return true;//是否走过
else if(mp[x][y][z]=='#') return true;
return false;
}
int bfs(){
queue<man> bfs_;
man temp,head;
head.x=x_begin;
head.y=y_begin;
head.z=z_begin;
head.step=0;
bfs_.push(head);
while(!bfs_.empty()){
head = bfs_.front();
if(head.x==x_end&&head.y==y_end&&head.z==z_end)
return head.step;
bfs_.pop();
for(int i=0;i<6;i++){
temp.x = head.x+go[i][0];
temp.y = head.y+go[i][1];
temp.z = head.z+go[i][2];
if(check(temp.x,temp.y,temp.z)) continue;
temp.step=head.step+1;
is[temp.x][temp.y][temp.z]=true;
bfs_.push(temp);
}
}
return 0;
}
int main(){
while(scanf("%d%d%d",&a,&b,&c)!=-1){
getchar();
if(a==0&&b==0&&c==0) break;
else{
memset(is,0,sizeof(is));
//memset(mp,0,sizeof(mp));
for(int i=0;i<a;i++){
for(int j=0;j<b;j++){
for(int k=0;k<c;k++){
cin>>mp[i][j][k];
if(mp[i][j][k]=='S'){
x_begin = i;
y_begin = j;
z_begin = k;
}
if(mp[i][j][k]=='E'){
x_end = i;
y_end = j;
z_end = k;
}
}
}
getchar();
}
}
int flag = bfs();
if(flag==0) printf("Trapped!\n");
else printf("Escaped in %d minute(s).\n",flag);
}
}
组队赛
比赛链接:https://codeforces.com/gym/102780
写完个人赛发现都已经快九点了。留着下轮一块写吧。