SCNUOJ 2019 软件学院 团体程序设计天梯赛 选拔赛 题解

3n+1 问题(10)


Problem Description

考虑以下算法:

1. input n
2. print n
3. if n == 1 then STOP
4.     if n is odd then n = 3 * n + 1
5.     else n = n / 2
6. GOTO 2.

给定输入 22,将输出以下数字序列
22\ 11\ 34\ 17\ 52\ 26\ 13\ 40\ 20\ 10\ 5\ 16\ 8\ 4\ 2\ 1
据推测,对于任何输入值,上述算法都将终止。尽管算法很简单,但不知道这个猜想是否正确。
给定输入 n,可以确定输出的数字(包括 1)。对于给定的 n,这称为 n 的循环长度。在上面的例子中,22 的循环长度是 16。
对于任何两个数字 i 和 j,您将确定 i 和 j 之间(包括 i 和 j)所有数字的最大循环长度。

Input

输入将由一系列整数 i 和 j 组成(i ≤ j),每行一对整数(输入保证不超过 10 行)。所有整数将小于 100000 且大于 0。您应该处理所有整数对,并且对于每对确定 i 和 j 之间(包括 i 和 j)的所有整数的最大循环长度。

Output

对于每对输入整数 i 和 j,您应该输出 i,j,i 和 j 之间的最大循环长度。这三个数字应由一个空格分隔,一行中三个数字,每行输入一行输出。整数 i 和 j 必须以与它们出现在输入中相同的顺序出现在输出中(在同一行上)。

Sample Input

1 10
100 200
201 210
900 1000

Sample Output

1 10 20
100 200 125
201 210 89
900 1000 174

Hint
思路:

暴力打表or直接模拟

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int num[100010];
int cnt(int n)
{
    int ans=0;
    while(n!=1)
    {
        if(n%2==1)
            n=3*n+1;
        else
            n/=2;
        ans++;
    }
    return ans+1;
}
void init()
{
    for(int i=1;i<=100000;i++)
        num[i]=cnt(i);
}
int main()
{
    init();
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int maxx=-1;
        for(int i=n;i<=m;i++)
            maxx=max(maxx,num[i]);
        printf("%d %d %d\n",n,m,maxx);
    }
    return 0;
}

喵星人(5)


Problem Description

据说 CGY 家里的喵星人很聪明,会计算十以内的加法。例如:现有数字 1,2,喵星人会用“Mia~Mia~Mia~”来表达答案是 3。
现在有请你来写一个程序,模拟这个过程。

Input

输入在一行中给出两个区间在 [1,9] 的正整数 A 和 B,用空格分隔

Output

在一行中输出有 A+B 个“Mia~”(不包含引号)。

Sample Input

2 1

Sample Output

Mia~Mia~Mia~

Hint
思路:

题解?!//大家都过了,没什么好说啦

#include <iostream>

using namespace std;

int main()
{
    int a,b;
    string mia="Mia~";
    cin>>a>>b;
    for(int i=0;i<a+b;i++)
        cout<<mia;
    cout<<endl;
    return 0;
}

变换数字(20)


Problem Description

开学的第一节课是高数课,由于翁哥第一节课讲的东西实在是太无聊了,FS 开始了“钓鱼”模式。SLF 看 FS 实在是太困了,就给了他一个问题:现在黑板有一个数字 N,那么将这个数字反转相加M次之后的数字是多少?例如现在的数字 N=87,M=4,那么 87+78 = 165,165+561=726,726+627=1353,1353+3531=4884,最后的答案为 4884。
FS 玩了十分钟后觉得太无聊了,于是把这个 easy problem 交给你。

Input

输入一行,N,M,其中 N 为不超过 100 位的正整数,N 为十进制数,M 为整数且 0<=M<=30

Output

输出一行 ans,其中 ans 代表最后的答案

Sample Input

87 4

Sample Output

4884

Hint

87+78 = 165
165+561 = 726
726+627 = 1353
1353+3531=4884

思路:

方法一:C++模拟大数相加,即获得一个数反转过来相加即可
方法二:用JAVA得BigInteger输入,然后reserve相加完事
题目都说了最大有100位的非负整数,当然是用大数啦,不然怎么可能是道20分题:)

#include <iostream>
#include <cmath>
 
using namespace std;
 
string get_add(string s,int n){
    int len = s.size();
    string t = s;
    for(int i = 0;i < ceil((double)len);i++){
        s[i] = (char) (s[i]+t[len-i-1]-'0');
    }
    for(int i = len-1;i >= 1;i--){
        if(s[i]-'0'>=n){
            s[i-1] = (char) (s[i-1]+1);
            s[i] = (char) (s[i]-n);
        }
    }
    t = "";
    if(s[0]-'0'>=n){
        t = "1";
        s[0] = (char)(s[0]-n);
    }
    return t+s;
}
 
int main(){
    string n;
    int m;
    cin>>n>>m;
    while(m--){
        n = get_add(n,10);
    }
    cout<<n;
    return 0;
}

简单的问题(15)


Problem Description

现在给你一个包含 0~9 和 A~F 的字符串,你需要求出在这个字符串中出现次数最多的字符,然后你需要求出这个字符串组成的十六进制转换为十进制的数。

Input

第一行读入一个整数 T(1≤T≤10),代表数据组数。
接下来给出 T 行,
每行给出这个字符串
输入保证数组长度 ≤ 15

Output

每组输出两行
第一行表示出现次数最多的字符和出现的次数,用空格隔开。若有相同的次数,则输出字典序最小的。
第二行表示转换的十进制数

Sample Input

1
22011

Sample Output

4884

Hint
思路:

按题意模拟,注意一下输出的数字要用long long来存

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        string str;
        cin>>str;
        int n=str.length(),cnt[20];
        long long number=0;
        memset(cnt,0,sizeof(cnt));
        for(int i=n-1;i>=0;i--)
        {
            if('A'<=str[i]&&str[i]<='F')
            {
                cnt[str[i]-'A'+10]++;
                number+=pow(16,n-1-i)*(str[i]-'A'+10);
            }
            else
            {
                cnt[str[i]-'0']++;
                number+=pow(16,n-1-i)*((str[i]-'0'));
            }
        }
        int maxx=-1,pos;
        char maxxc;
        for(int i=0;i<16;i++)
        {
            if(maxx<cnt[i])
            {
                maxx=cnt[i];
                pos=i;
            }
        }
        if(pos<10)
            maxxc=(char)('0'+pos);
        else
            maxxc=(char)('A'+pos-10);
        cout<<maxxc<<" "<<maxx<<endl;
        cout<<number<<endl;
    }
    return 0;
}

CGY 的第一课(5)


Problem Description

CGY开始学习编程了,今天是他上的第一课,老师让他把输入的数字照着原样输出。

Input

输入一个实数N(-10^{10}<=N<=10^{10})

Output

输出输入的数字N

Sample Input

123.88

Sample Output

123.88

Hint
思路:

实数包括所有小数和整数,所以要用字符串输入输出

#include <iostream>

using namespace std;

int main()
{
    string in;
    cin>>in;
    cout<<in<<endl;
    return 0;
}

轰炸(10)


Problem Description

SLF 现在正准备用他的超能力轰炸一片区域,在这片区域中有 N 座建筑,每个建筑的血量都是 M,SLF 携带的炮弹只能对一座建筑造成 X 点伤害,但发射炮弹需要消耗他的能量,第一发炮弹的能量为 3 点,并且发射炮弹需要的能量每次递增两点,即下一发的能量=上一发的能量+2,幸运的是每当 SLF 摧毁了一座建筑,他都可以获得 Y 点能量,SLF 一开始共有 Z 点能量,现在 SLF 想知道他最多可以炸掉多少建筑。

Input

第一行读入一个整数 T,代表数据组数。
接下来给出T行,
每行给出N,M,X,Y,Z
1≤T≤10,1≤N≤100,1≤M≤100,1≤X≤M,1≤Y≤100,1≤Z≤100

Output

每组数据输出一行,代表最多可以炸掉多少建筑

Sample Input

1
5 5 2 1 20

Sample Output

1

Hint

摧毁一座建筑需要3发炮弹,需要的能量为3+5+7=15,摧毁一座建筑后获得1点能量,所以总能量变为20-15+1=6,第四发炮弹发射需要能量为9点,无法再次发射,所以总共摧毁一座建筑

思路:

按题意模拟计算。注意考虑可摧毁数量大于n的时候。

#include <iostream>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        int n,m,x,y,z,t;
        cin>>n>>m>>x>>y>>z;
        if(m%x) t = (m/x)+1;
        else    t = m/x;
        int s1 = t*t + 2*t;
        m = n;
        while(n>0){
            z-=s1;
            if(z<0) break;
            n--;
            s1+=t*t*2;
            z+=y;
        }
        cout<<m-n<<endl;
    }
}

LXY 背单词(20)


Problem Description

LXY终于开始学英语了,然而他的记忆力有限,每当他看完一段文章,他最多记住每个字母开头对应的一个单词。“既然只能记住一个单词,那么当然记住最大的那个啊”——LXY。然而怎么定义最大这个概念呢,LXY决定按照字典顺序,记住最大的那个单词。
现在我们知道LXY即将会看到的文本,你能确定他会记住哪些单词么?
注:输入文本中的所有不同单词不计大小写,比如“Apple”,“aPPle”或“APPLE”都被视为相同的单词apple

Input

输入一串文本,直至文件结束。

Output

按照每个字母开头对应的字典序最大的单词,没有则不输出,单词统一由小写字母组成,一行输出一个。
注:任何不属于字母的符号都会区分单词,包括回车、数字。

Sample Input

Adventures in Disneyland
Two blondes were going to Disneyland when they came to a fork in the
road. The sign read: "Disneyland Left."
So they went home.

Sample Output

adventures
blondes
came
disneyland
fork
going
home
in
left
road
so
two
when

Hint
思路:

方法一:直接按题意模拟,注意输入格式的问题
方法二:用sstream将非字符赋值为空格,分割出单词之后模拟即可

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
string word[30];
void init()
{
    for(int i=0;i<26;i++)
        word[i]="0";
}
int main()
{
    string in;
    init();
    while(getline(cin,in))
    {
        transform(in.begin(),in.end(),in.begin(),::tolower);
        int n=in.length();
        string thisword="";
        for(int i=0;i<=n;i++)
        {
            if((in[i]>='a'&&in[i]<='z')&&i!=n)
            {
                thisword+=in[i];
            }
            else if(thisword.length()>0)
            {
                int pos=(thisword[0]-'a');
                if(thisword>word[pos])
                    word[pos]=thisword;
                thisword="";
            }
        }
    }
    for(int i=0;i<26;i++)
        if(word[i]!="0")
            cout<<word[i]<<endl;
    return 0;
}

垃圾装箱(15)


Problem Description

CGY 老是说自己是垃圾,于是有一天,CGY 做梦梦到了自己真的变成了垃圾,而且是很多很多的垃圾。
众所周知 LXY 是一个环保主义者,于是学院重点垃圾 CGY 的回收处理工作就交由 LXY 来全权负责。
垃圾 CGY 分为三类:棕色 CGY、绿色 CGY 和透明 CGY。LXY 分别从宿舍、课室和机房收集来三个箱子(毕竟垃圾 CGY 只会被丢在这几个地方),每个箱子都包含指定数量的棕色、绿色和透明 CGY。LXY 需要移动这些垃圾 CGY,使得每个箱子里仅包含一种 CGY,这样才方便迫害回收再利用。
问题在于 LXY 太胖了,每次移动 CGY 都需要消耗一定的力气,于是他想尽量减少移动的数量。//虽然 LXY 把 CGY 丢下楼的难度比吃生菜还简单(甚至能一次丢好几个)
出于此目的,可以假设每个箱子都足够大(毕竟 CGY 体积小而且还算是限定版垃圾)。

Input

输入包括多行,每行包含由空格分隔的 ⑨ 个整数。每三个整数表示第 i 个箱子中的棕色、绿色和透明 CGY 的数量。例如:
10\ 15\ 20\ 30\ 12\ 8\ 15\ 8\ 31
表示第一个箱子有 20 个透明 CGY,第二个箱子有 12 个绿色 CGY,第三个箱子有 15 个棕色 CGY。
垃圾 CGY 总数不会超过 2^31。

Output

对于每行输入,应输出每个箱子装的 CGY 的种类和最少的 CGY 移动数量。
大写字母 'B','G','C' 分别表示棕色、绿色和透明,字符串中的第 i 个字符表示第 i 个箱子中装的 CGY 的种类。
CGY 移动数量应在种类字符串后面,用空格隔开。
如果有多个解,则应输出字典序最小的种类字符串。

Sample Input

1 2 3 4 5 6 7 8 9
5 10 5 20 10 5 10 20 10

Sample Output

BCG 30
CBG 50

Hint
思路:

题目意思是三个混合装有三种不同物品的箱子,移动物品使得三个箱子只装同一种东西并要求移动的总数量最少。
因为只有BCG三种情况,枚举情况为321=6种,所以直接枚举所有箱子可能的情况即可,然后取最小值,顺带要注意题目中的字典序要求。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
string part[6]={"BCG","BGC","CBG","CGB","GBC","GCB"};
int part_sum[6],r[3][3];
int main()
{
    while(~scanf("%d",&r[0][0]))
    {
        scanf("%d%d",&r[0][1],&r[0][2]);
        for(int i=1;i<3;i++)
            for(int j=0;j<3;j++)
                scanf("%d",&r[i][j]);
        memset(part_sum,0,sizeof(part_sum));
        part_sum[0]=r[1][0]+r[2][0]+r[0][1]+r[1][1]+r[0][2]+r[2][2];
        part_sum[1]=r[1][0]+r[2][0]+r[0][1]+r[2][1]+r[0][2]+r[1][2];
        part_sum[2]=r[0][0]+r[2][0]+r[0][1]+r[1][1]+r[1][2]+r[2][2];
        part_sum[3]=r[0][0]+r[1][0]+r[0][1]+r[2][1]+r[1][2]+r[2][2];
        part_sum[4]=r[0][0]+r[2][0]+r[1][1]+r[2][1]+r[0][2]+r[1][2];
        part_sum[5]=r[0][0]+r[1][0]+r[1][1]+r[2][1]+r[0][2]+r[2][2];
        int minn=99999999,pos=-1;
        for(int i=0;i<6;i++)
        {
            if(part_sum[i]<minn)
            {
                minn=part_sum[i];
                pos=i;
            }
        }
        cout<<part[pos]<<" "<<minn<<endl;
    }
    return 0;
}

301 网络修复(25)


Problem Description

这个学期以来,信息中心301的有线网络一直用不了,LXY和CGY为此很苦恼。在院长一声令下修好了灯之后,网络中心的人终于来301修复网络了。老师经过排查告诉LXY:301的交换机有多余的回路存在,导致局域网不能正常的工作。为了解决这个问题,必须拆掉多余的线路,保证任意两台交换机之间只有一条联通路存在。同时,由于网线的材质不同,每一条网线的延迟也不一样,LXY希望最后留下来的线路的延迟最小。
然而CGY在垃圾的梦中,LXY在捡垃圾,你能告诉他们该留下的线路延迟最小是多少么?

Input

第一行两个正整数n(n<=100),k(k<=n^2)
接下来的k行每行三个正整数i j m,表示i,j两台交换机之间有网线联通,延迟为m。

Output

最后留下的网线的最小延迟。

Sample Input

5 5
1 2 8
1 3 1
1 5 3
2 4 5
3 4 2

Sample Output

11

Hint
思路:

最小生成树模板题

#include <iostream>
#include <algorithm>
#include <string>
 
using namespace std;
 
struct temp{
    int i,j,c;
}a[10010];
 
int f[110];
 
int find_father(int x){ return f[x]==x?x:f[x] = find_father(f[x]);}
 
bool cmp(temp&s1,temp&s2){return s1.c<s2.c;}
 
int main(){
    int n,m,total = 0;
    cin>>n>>m;
    for(int i = 1;i<=n;i++) f[i] = i;
    for(int i = 0;i<m;i++) cin>>a[i].i>>a[i].j>>a[i].c;
    sort(a,a+m,cmp);
    for(int i = 0;i<m;i++){
        int x = a[i].i,y = a[i].j,c = a[i].c;
        if(find_father(x) != find_father(y)){
            f[find_father(x)] = find_father(y);
            total+=c;
        }
    }
    cout<<total;
    return 0;
}

Best match(25)


Problem Description

总所周知,大名鼎鼎的 JB-ICPC 是一个三人组队的电子竞技比赛,只有三人齐心协力优势互补才能在比赛中 AC 尽可能多的题目。
香农先修班选出了 ⑨ 位优秀的 JBer,由他们进行组队参加新一年的 JB-ICPC 区域赛,争取为 SCNUSE 拿下尽可能多的奖,甚至是 World Final 名额。
SLF 和 FS 作为新一届先修班的负责人犯难了,因为他不知道如何将这几个人分成三个组,毕竟有些人的优势是重叠的导致总共能 AC 的题目数量较少。
又或者说有些人根本不想和某些人一起组队,毕竟人和人之间的关系总是要比算法难处理得多,对吧……
老前辈 LXY 给出战术指导换家,把所有能组合在一起的三人组合得出的 AC 题数统计起来,选出不重合的三组队员使得三队的 AC 数最高,就可以保证三队都能稳定打铁拿奖了。
SLF 和 FS 只得照办,统计出所有可能的组合,然后丢给决策自动机 CGY 来处理。问题在于,CGY 还在变成垃圾的梦里没醒来,那你懂我意思了吧?

Input

输入包含最多 100 个测试样例。
每个样例第一行是一个整数 n(0 < n < 81),即可能的组合数。
接下来的 n 行,每行包含 4 个正整数 a,b,c,s(1 ≤ a < b < c ≤ 9,0 < s < 10000),这意味着(a,b,c)这个组合可以 AC s 道题。(输入保证不会有重复出现的组合)
最后一组样例只有一个 0,不需要处理。

Output

对于每个测试样例,输出样例编号和最高分。如果组不成三支队,输出 -1。

Sample Input

3
1 2 3 1
4 5 6 2
7 8 9 3
4
1 2 3 1
1 4 5 2
1 6 7 3
1 8 9 4
0

Sample Output

Case 1: 6
Case 2: -1

Hint
思路:

n最大81,所以直接DFS暴力搜索,因为搜索次数最大为C(3,80),不会超时。
用DFS列出所有的组合的可能性,最后判断当前组合是否符合题意即没有重复的队员,符合就更新一下最大值即可。

#include <iostream>
#include <cstring>
 
using namespace std;
 
int n,a[100][4],t[3],res;
bool f[100];
 
void dfs(int curn){
    if(curn == 3){
        int curac = 0,tt;
        bool flag[10] = {false};
        for(int i = 0;i<3;i++){
            tt = t[i];
            curac+=a[tt][3];
            for(int j = 0;j<3;j++)
                flag[a[tt][j]] = true;
        }
        for(int i = 1;i<=9;i++)
            if(!flag[i]) return;
        res = max(res,curac);
        return;
    }
    for(int i = 0;i<n;i++){
        if(!f[i]){
            f[i] = true;
            t[curn] = i;
            dfs(curn+1);
            f[i] = false;
        }
    }
}
 
int main(){
    int k = 0;
    while(cin>>n &&n!=0){
        for(int i = 0;i<n;i++)
            cin>>a[i][0]>>a[i][1]>>a[i][2]>>a[i][3];
        memset(f,false,sizeof(f));
        res = -1;
        dfs(0);
        cout<<"Case "<<++k<<": "<<res<<endl;
    }
    return 0;
}

电子字典(25)


Problem Description

slf正在为他的英语考试做准备,为此他给自己写了一个电子字典,字典含有以下功能:

  1. 添加
    添加操作的格式为:insert 单词 频次
    例如:insert helpful 5
    意思是添加helpful这个单词,频次为5。如果再次执行insert helpful 5 操作时,helpful的频次变为10。
  2. 删除
    删除格式为:delete 单词
    例如:delete helpful
    意思是删除字典中helpful这个单词。
    若当前版本的电子字典中没有要删除的单词,则输出”Empty”(不含引号)。
  3. 查询
    查询的格式为:query 单词
    例如:query ful
    意思是查询当前版本的电子字典中以ful结尾的所有单词词频总和,然后输出结果。
Input

第一行读入一个整数 T,代表数据组数。
每组数据的第一行读入一个整数 N 代表操作数。
接下来 N 行,每行形容一个操作。
保证数据满足 1≤T≤10, 1≤N≤1000,insert操作的字符串总长度之和≤30000,所有字符串长度≤10000
输入只有小写字母

Output

根据题目要求输出

Sample Input

1
6
insert helpful 8
query ful
insert careful 9
query ful
delete helpful
query ful

Sample Output

8
17
9

Hint
思路:

按题意模拟,把输入的每一个单词都取出其所有后缀,然后插入map中。查询时直接查后缀的个数。
注意:某单词有可能是另外一个单词的后缀,例如单词e是Apple的后缀,所以删除某单词所有后缀的时候要注意有可能会把另外一个单词给删掉。
比较好想的办法就是采用两个map,一个dic记录后缀,一个com记录完整单词。

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;

map<string,int> dic,com;//dic记录后缀,com记录完整单词,用于del
void ins(string str,int key);
void del(string str);
int que(string str);

int main()
{
    int t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        while(n--)
        {
            string op,str;
            cin>>op>>str;
            if(op=="insert")
            {
                int key;
                cin>>key;
                ins(str,key);
            }
            else if(op=="delete")
            {
                del(str);
            }
            else
            {
                cout<<que(str)<<endl;
            }
        }
        dic.clear();
        com.clear();
    }
    return 0;
}
void ins(string str,int key)
{
    if(com.count(str)==0)
        com.insert(map<string,int>::value_type(str,key));
    else
        com[str]+=key;

    int n=str.length();
    for(int i=0;i<n;i++)
    {
        string insstr=str.substr(n-i-1);
        if(dic.count(insstr)==0)
            dic.insert(map<string,int>::value_type(insstr,key));
        else
            dic[insstr]+=key;
    }
}
void del(string str)
{
    if(com.count(str)==0)
        cout<<"Empty"<<endl;
    else
    {
        int num=com[str],n=str.length();
        for(int i=0;i<n;i++)
        {
            string delstr=str.substr(n-i-1);
            dic[delstr]-=num;
        }

        com.erase(str);
    }
}
int que(string str)
{
    if(dic.count(str)==0)
        return 0;
    return dic[str];
}

体育老师的烦恼(25)


Problem Description

学期结束了,学校准备将学生的体育成绩进行一个排名,具体排名规则如下。
首先按照学生的期末成绩进行排序,成绩高的在前。
其次是按照学生的期中成绩 40% 和平时成绩 60% 相加后的成绩进行排序,成绩高的在前。
最后是按照学生的学号进行排序,学号小的在前。
PS:所有学生的学号长度一致,数字小的在前。
数学不好的体育老师找到了 CGY 来帮他解决这个问题,CGY 觉得太简单的于是丢给背锅侠 FS 来做。由于这段时间 FS 实在是太忙了,于是将问题抛给了你。

Input

输入 n 表示学生人数(n<=10000),接下来的 n 行,每行从前往后给出学生的学号(位数为 11 位),学生姓名(不大于 10 位的字符串,无空格),期末成绩(不大于 100 的非负整数),期中成绩(不大于 100 的非负整数),平时成绩(不大于 100 的非负整数)。

Output

输出 n 行,一人一行,输出格式与输入格式相同

Sample Input

6
20152000100 Tim 60 60 60
20052001323 Su 90 60 100
20173999099 Lily 90 90 80
20163334123 Ming 90 90 80
20143727429 Boy 90 80 90
20184732198 Tom 100 90 90

Sample Output

20184732198 Tom 100 90 90
20143727429 Boy 90 80 90
20052001323 Su 90 60 100
20163334123 Ming 90 90 80
20173999099 Lily 90 90 80
20152000100 Tim 60 60 60

Hint
思路:

本题考察结构体排序,不过有个注意点是要注意浮点数的精度误差。
最佳的做法就是采用整数来存,然后将期中成绩4,平时成绩6再来比较即可。
//float精度比double低所以会丢失一些精度,用float反而会AC,用double不考虑精度问题的话肯定是会WA的。

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
struct Student{
    string snumber;
    string sname;
    int ends;
    int mid;
    int pin;
    int quan;
};

bool cmp(Student student1,Student student2)
{
    if(student1.ends==student2.ends)
    {
        if(student1.quan==student2.quan)
        {
            return student1.snumber<student2.snumber;
        }
        else
        {
            return student1.quan>student2.quan;
        }
    }
    else
        return student1.ends>student2.ends;
}

Student student[10010];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>student[i].snumber>>student[i].sname>>student[i].ends>>student[i].mid>>student[i].pin;
        student[i].quan=student[i].mid*4+student[i].pin*6;
    }
    sort(student,student+n,cmp);
    for(int i=0;i<n;i++)
    {
        cout<<student[i].snumber<<" "<<student[i].sname<<" "<<student[i].ends<<" "<<student[i].mid<<" "<<student[i].pin<<endl;
    }
    return 0;
}

避铳(30)


Problem Description

我们希望在一块 n × n 的棋盘上放置 n 个象棋中的車,但受到以下限制:
· 第 i 个車只能放置在一个给定的左上角为 (xl[i],yl[i]) 和右下角为 (xr[i],yr[i]) 的矩形内,其中 1 ≤ i ≤ n,1 ≤ xl[i] ≤ xr[i] ≤ n,1 ≤ yl[i] ≤ yr[i] ≤ n。
· 任意两个車都不可以相互攻击,也就是不能放铳(迫真),也就是说,没有两个車可以占据同一列或同一行。
你的任务是找到有没有满足上述条件的車的放置。

Input

输入包含几个测试用例。每个的第一行包含一个整数 n(n ≤ 5000),即棋盘的大小。然后是 n 行,其中的第 i 行给出了 xl[i],yl[i],xr[i] 和 yr[i]。输入最后是一个 0,不需要处理。

Output

如果有这种放置 play,输出 "Tenpai",反之输出 "Ron"。

Sample Input

8
1 1 2 2
5 7 8 8
2 2 5 5
2 2 5 5
6 3 8 6
6 3 8 5
6 3 8 8
3 6 7 8
0

Sample Output

Tenpai

Hint
思路:

因为車是只能攻击同一行或同一列的車,所以可以将这个二维问题分解为两个一维问题。
是否能在x上的若干个区域内选出n个不同的x值,在y上的若干个区域内选出n个不同的y值。(每个区域只能选一个值)
若都能满足则输出"Tenpai",不能则输出"Ron"。
可以用贪心法来处理这个一维问题。
设若干个区域为[l,r],对r值进行升序排序,如果r值相同则根据l值进行升序排序。
排完序之后从前往后遍历,再从li遍历取第一个没有被标记的值,如果这个值大于ri,则表明没有解,小于等于ri则将这个值标记。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

struct temp{
    int x1,x2;
    int y1,y2;
}a[5010];

bool cmp1(const temp&s1,const temp&s2){
    if(s1.x2==s2.x2)
        return s1.x1<s2.x1;
    else
        return s1.x2<s2.x2;
}

bool cmp2(const temp&s1,const temp&s2){
    if(s1.y2==s2.y2)
        return s1.y1<s2.y1;
    else
        return s1.y2<s2.y2;
}

bool visx[5010],visy[5010],flag;

int main(){
    int n;
    while(cin>>n && n!=0){
        memset(visx,false,sizeof(visx));
        memset(visy,false,sizeof(visy));
        flag = true;
        struct temp t;
        for(int i = 0;i<n;i++){
            cin>>t.x1>>t.y1>>t.x2>>t.y2;
            a[i] = t;
        }
        if(flag){
            sort(a,a+n,cmp1);
            for(int i = 0;i<n;i++){
                t = a[i];
                int curx = t.x1,x2 = t.x2;
                while(visx[curx]){//寻找第一个未标记值
                    curx++;
                }
                if(curx>x2){//判断是否这个值是否超过当前区间最大值
                    flag = false;
                    break;
                }
                visx[curx] = true;
            }
        }
        if(flag){
            sort(a,a+n,cmp2);
            for(int i = 0;i<n;i++){
                t = a[i];
                int cury = t.y1,y2 = t.y2;
                while(visy[cury]){
                    cury++;
                }
                if(cury>y2){
                    flag = false;
                    break;
                }
                visy[cury] = true;
            }
        }
        if(flag)
            cout<<"Tenpai"<<endl;
        else
            cout<<"Ron"<<endl;
    }
    return 0;
}

总结:

//这次比赛涌现了好多meng男,tqltql

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345