题1 国际象棋(chess)
【问题描述】 有N个人要参加国际象棋比赛,该比赛要进行K场对弈。每个人最多参加2场对弈,最少参加0场对弈。每个人都有一个与其他人都不相同的等级(用一个正整数来表示)。在对弈中,等级高的人必须用黑色的棋子,等级低的人必须用白色的棋子。每一个人最多只能用一次黑色的棋子和一次白色的棋子。为了增加比赛的可观度,观众希望K场对弈中双方的等级差的总和最小。 比如有7个选手,他们的等级分别是30; 17; 26; 41; 19; 38; 18,要进行3场比赛。最好的安排是Player 2 vs Player 7, Player7 vs Player 5 , Player 6 vs Player 4,此时等级差的总和等于(18-17) + (19-18) + (41-38) = 5达到最小。 【输入格式】 第一行两个正整数N,K。 接下来有N行,第i行表示第i-1个人等级。 【输出格式】 在第一行输出最小的等级差的总和。 【输入样例】 7 3 30 17 26 41 19 38 18 【输出样例】 5 【数据范围】 在90%的数据中,1≤N≤3000 在100%的数据中,1≤N≤100000 保证所以输入数据中等级的值小于108,1≤K≤N-1
tag:贪心 排序
思路:在这种两两对弈的情况下,有n*(n-1)/2种可能性,但是原题已限定条件(每一个人最多只能用一次黑色的棋子和一次白色的棋子,即只能和数值比自己大的选择1个,比自己小的选择1个),极大的缩小了选择的可能。由于k<=n-1,易得贪心策略----在排序后相邻数值的差放入新数组,再次排序选最小的k个。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define maxn 100010 using namespace std; int n,m,i,cnt,a[maxn],s[maxn]; long long ans; int read() { int x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } int main() { //freopen("chess.in","r",stdin); //freopen("chess.out","w",stdout); scanf("%d%d",&n,&m); for(i=1;i<=n;++i) a[i]=read(); sort(a+1,a+n+1); for(i=1;i<n;++i) s[i]=a[i+1]-a[i]; sort(s+1,s+n); for(i=1;i<=m;++i) ans+=s[i]; cout<<ans<<endl; return 0; }
题2 单词化简(abbreviate)
【题目描述】 最近情报人员得到了一些经过加密的文章,每个单词都很长。破译人员想到先把单词化简一下,方法是把每个单词尽量取短些的前缀,但所取的前缀不能是其他单词的前缀。 这个任务现在就交给你来完成。 解释:“字符串s1是s2的前缀”是说把字符串s2的后面去掉某些,只保留与s1相同长度是,s2就与s1完全相同。如:“abc“是”abcaade“和”abc“的前缀,但不是”abadc“的前缀。 数据范围 单词数N,1<=n<=50; 每个单词长度不超过50;并且都是由小写字母构成。 保证所给单词没有一个单词是另一个单词的前缀。 【输入文件】 第一行一个整数N,表示单词的个数。 下面有N行,每行一个单词。 【输出文件】 共N行,每行一个单词,是对应上面N个单词化简后的单词。 【样例输入1】 3 abc efg ijh 【样例输出1】 a e i 【样例输入2】 3 aac aad aae 【样例输出2】 aac aad aae
tag:贪心 字符串
思路:数据量较小,找到每个字符串与其他所有字符串最长的重合部分截至点。优化可考虑按字典序排序,由于字符串与上下两个的契合度最高,上下比较即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 char a[60][60],n,i,j,k; 7 int ans[60]; 8 int main() 9 { 10 //freopen("abbreviate.in","r",stdin); 11 //freopen("abbreviate.out","w",stdout); 12 scanf("%d",&n); 13 for(i=1;i<=n;++i) scanf("%s",a[i]); 14 for(i=1;i<=n;++i) 15 for(j=1;j<=n;++j){ 16 if(i!=j){ 17 int ret=0; 18 for(k=0;k<strlen(a[i])&&k<strlen(a[j]);++k){ 19 if(a[i][k]==a[j][k]) ret++; 20 else{ 21 ans[i]=max(ret,ans[i]); 22 break; 23 } 24 } 25 } 26 } 27 for(i=1;i<=n;++i){ 28 for(j=0;j<=ans[i];++j) printf("%c",a[i][j]); 29 printf(" "); 30 } 31 return 0; 32 }
题3 火星上的加法运算(madition)
【问题描述】 最近欢欢看到一本有关火星的书籍,其中她被一个加法运算所困惑,由于她的运算水平有限,想向你求助,作为一名优秀的程序员,你当然义不容辞。 【文件输入】 输入文件第一行输入一个运算的进制N(2<=n<=36),接下来的两行为需要进行运算的字符,其中每个字符串的长度不超过200位,其为N进制的数,其中包括0-9以及a-z(代表10-35)。 【文件输出】 输出文件内容为在N进制下这两个数的和。 【输入样例1】 20 1234567890 abcdefghij 【输出样例1】 bdfi02467j 【输入样例2】 20 99999jjjjj 9999900001 【输出样例2】 iiiij00000
tag:高精度
思路:模拟高精度加法,注意去前导0。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 char ys1[50],a1[300],b1[300],c[300]; 7 int ys2[200],a2[300],b2[300],n,i,lena,lenb,lenc; 8 void init() 9 { 10 for(i=0;i<=9;++i) ys1[i]='0'+i; 11 for(i=10;i<=35;++i) ys1[i]='a'+i-10; 12 for(i=48;i<=57;++i) ys2[i]=i-48; 13 for(i=97;i<=122;++i) ys2[i]=i-87; 14 } 15 int main() 16 { 17 //freopen("Madition.in","r",stdin); 18 //freopen("Madition.out","w",stdout); 19 init(); 20 scanf("%d",&n); 21 scanf("%s",a1); 22 scanf("%s",b1); 23 lena=strlen(a1),lenb=strlen(b1),lenc=max(lena,lenb); 24 for(i=0;i<lena;++i) a2[lena-i-1]=ys2[a1[i]]; 25 for(i=0;i<lenb;++i) b2[lenb-i-1]=ys2[b1[i]]; 26 for(i=0;i<lenc;++i){ 27 c[i]+=a2[i]+b2[i]; 28 c[i+1]+=c[i]/n; 29 c[i]%=n; 30 } 31 if(c[lenc]) lenc++; 32 while(!c[lenc-1]&&lenc-1) lenc--; 33 for(i=lenc-1;i>=0;--i) printf("%c",ys1[c[i]]); 34 return 0; 35 }
题4 队列安排(arrange)
【问题描述】 一个学校里老师要将班上N个同学排成一列,同学被编号为1~N,他采取如下的方法: 1. 先将1号同学安排进队列,这时队列中只有他一个人; 2. 2~N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1~i -1中某位同学(即之前已经入列的同学)的左边或右边; 3. 从队列中去掉M(M<N)个同学,其他同学位置顺序不变。 在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。 【输入文件】 输入文件arrange.in的第1行为一个正整数N,表示了有N个同学。 第2~第N行,第i行包含两个整数k,p,其中k为小于i的正整数,p为0或者1。若p为0,则表示将i号同学插入到k号同学的左边,p为1则表示插入到右边。 第N+1行为一个正整数M,表示去掉的同学数目。 接下来M行,每行一个正整数x,表示将x号同学从队列中移去,如果x号同学已经不在队列中则忽略这一条指令。 【输出文件】 输入文件arrange.out仅包括1行,包含最多N个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。 【样例输入】 4 1 0 2 1 1 0 2 3 3 【样例输出】 2 4 1 【样例说明】 将同学2插入至同学1左边,此时队列为: 2 1 将同学3插入至同学2右边,此时队列为: 2 3 1 将同学4插入至同学1左边,此时队列为: 2 3 4 1 将同学3从队列中移出,此时队列为: 2 4 1 同学3已经不在队列中,忽略最后一条指令 最终队列: 2 4 1 【数据规模与约定】 对于20%的数据,有N≤10; 对于40%的数据,有N≤1000; 对于100%的数据,有N, M≤100000。
tag:链表
思路:裸的链表。(可以不用像我写的这么麻烦,你可以用下面这个来理解、当模版)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define maxn 100010 6 using namespace std; 7 int pre[maxn],Next[maxn],head,tail,i,n,m; 8 int read() 9 { 10 int x=0; 11 char ch=getchar(); 12 while(ch<'0'||ch>'9') ch=getchar(); 13 while(ch>='0'&&ch<='9'){ 14 x=x*10+ch-'0'; 15 ch=getchar(); 16 } 17 return x; 18 } 19 void add(int x,int y,int o) 20 { 21 if(o){ 22 if(y==tail){ 23 Next[y]=x; 24 pre[x]=y; 25 tail=x; 26 } 27 else{ 28 pre[x]=y; 29 Next[x]=Next[y]; 30 pre[Next[y]]=x; 31 Next[y]=x; 32 } 33 } 34 else{ 35 if(y==head){ 36 Next[x]=y; 37 pre[y]=x; 38 head=x; 39 } 40 else{ 41 Next[x]=y; 42 pre[x]=pre[y]; 43 Next[pre[y]]=x; 44 pre[y]=x; 45 } 46 } 47 } 48 void del(int x) 49 { 50 if(x==head){ 51 head=Next[x]; 52 pre[Next[x]]=0; 53 } 54 else if(x==tail){ 55 tail=pre[x]; 56 Next[pre[x]]=0; 57 } 58 else{ 59 Next[pre[x]]=Next[x]; 60 pre[Next[x]]=pre[x]; 61 } 62 pre[x]=Next[x]=0; 63 } 64 int main() 65 { 66 //freopen("arrange.in","r",stdin); 67 //freopen("arrange.out","w",stdout); 68 int y,o; 69 scanf("%d",&n); 70 head=tail=1; 71 for(i=2;i<=n;++i){ 72 y=read(); 73 o=read(); 74 add(i,y,o); 75 } 76 scanf("%d",&m); 77 for(i=1;i<=m;++i){ 78 y=read(); 79 if(pre[y]||Next[y]) del(y); 80 } 81 for(i=head;i;i=Next[i]) printf("%d ",i); 82 return 0; 83 }
┈━═┈━═┈━═┈━═┈━═┈━═┈━═┈━═华丽分割线┈━═┈━═┈━═┈━═┈━═┈━═┈━═┈━═☆
芒果君:其实这次题目的难度对我来说……然而只拿了一半分,比如链表我本来有足够信心拿全分结果少写了2行代码……出完成绩还没一刻钟就改到AK了,有点郁闷,不过听一听古风歌心情就好多啦~这个解题报告写得比较简略不过实在没什么好写的?怎么说呢,还是要把自己的状态调整好,千万不要随便受影响了,顺其自然吧。
结束。