A A+B问题
解法:同题意。
Trick:值得注意的是while。题目中说包含多组测试数据,也就是读入一组数据、处理、输出结果后继续读下一组输入数据,直到(“直到”==while)读取不到下一组数据为止,循环结束,主函数也return 0。
代码:
#include<iostream>
using namespace std;
int main()
{
//freopen("in","r",stdin);
int a, b;
while(cin>>a>>b)
{
cout<<a+b<<endl;
}
return 0;
}
B 魔法序列
题意:给一个二进制序列(没有前导0,如:“010”就是有前导0,而“10”就没有前导0),删除其中一位,使结果最大。
解法:贪心(算是一种YY),如果数字不包含0,那么去每一位的结果都一样(不用证明了吧~)。如果数字包含0,那么去掉从左边数第一个0的结果最优。例如:10010:去掉左边第二位(结果为:1010),一般不会小于去掉其它位的结果。列表是:0010、1010、1010、1000、1001。
Trick:全是1的情况,算是一个坑,如果没有注意的话,会wrong的莫名其妙。
代码:
#include<iostream>
using namespace std;
int main()
{
string s, ans;
while(cin>>s)
{
ans = "";
int n = s.length(); bool slipt = false;
for(int i = 0 ; i < n ; ++ i)
{
if(s[i]=='0'&&!slipt)
{
slipt = true;
continue;
}
if(i==n-1&&!slipt) continue;
ans += s[i];
}
cout<<ans<<endl;
}
return 0;
}
C 简单任务
题意:给你n个数字,求第k小的数字。
ps:某杨学长出数据的时候没有卡掉sort,就想出了卡内存的方法,而他又天真的认为java的输入很慢,2000ms不能过,就没有卡内存。
解法:因为java语言和其它语言的内存大小完全不一样,所以解法也不一样。
1、c++(桶排序):内存只有1024k,存不下1000000个数,但是可以开一个大小10010的int数组num还是够的,每输入一个数字a,就把num[a]++。这样输入所有的数字后,就会有序统计出每个数字的个数,这样再求第k小的数字就方便了,从小到大枚举,第k大的数字在哪个区间就行了。
2、java(sort也就是快排):java没限内存,直接开个大小1000010的int数组a,然后用Arrays.sort(a,0,n),最后输出a[k-1](从0开始,k-1就是第k大的)。不过不能用Scanner输入,而改用StreamTokenizer,否则会被卡时间的。
Trick:1024k的内存,存不下100000个数字。无耻的学长为了卡sort,而限制内存。比赛前就猜想到了,会有一片MLE的。。。
c++代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
int a[10010];
int main()
{
//freopen("in","r",stdin);
int n , k;
while(~scanf("%d%d",&n,&k))
{
memset(a, 0 ,sizeof a);
for(int i = 0; i < n ; ++ i)
{
int tmp;
scanf("%d",&tmp);
a[tmp] ++;
}
int j = 0;
int ans = 0;
for(int i = 0 ; i <= 10000 ; ++ i)
{
j += a[i];
if(j>=k)
{
ans = i;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
java代码:
import java.util.*;
import java.io.*;
public class Main {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
int[] a = new int[1000100];
StreamTokenizer input=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
while(input.nextToken()!=StreamTokenizer.TT_EOF)
{
int n = (int)input.nval;
input.nextToken();
int k = (int)input.nval;
for(int i = 0 ; i < n ; ++ i)
{
input.nextToken();
a[i] = (int)input.nval;
}
Arrays.sort(a,0,n);
System.out.println(a[k-1]);
}
}
}
D 拯救魔法少女
题意:给你一张n行m列的地图,最多有20个起点,1个终点,还有很多宝石(价值'0'-'9')。求从起点到终点的最短距离,在距离相等的情况下求最大的宝石获得情况。
解法:BFS(广度优先搜索)。只有一个终点,所以可以从终点搜到起点,第一次遇见起点的步数一定是最短的步数,然后求在这个步数遇见起点的最大价值。这里应用的dp的思想,每个点保存一个步数和价值,只有步数是前一步的步数加一才更新值(价值往大了更新),而且每个点只能入队列一次。这样就能统计出最短步数最大价值了。
Trick:没发现。
(自己画的,好丑。。。)
图中每个颜色代表不同步数可以到达这个点,只有在这个步数到达这个点才更新dp的值,而且每个点只入队一次。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n, m, anstep, ansnum;
char maps[55][55];
int fx[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
struct Point
{
int x, y;
Point(int x=0, int y=0):x(x),y(y) {}
}p;
struct node
{
int val, step;
}dp[55][55];
void init()
{
memset(dp, -1, sizeof dp);
memset(maps, 0, sizeof maps);
ansnum = -1; anstep = 1000000;
}
int value(int x, int y)
{
if(maps[x][y]<='9' && maps[x][y]>='0')
{
return maps[x][y] - '0';
}
return 0;
}
void bfs()
{
queue<Point> q;
q.push(p);
dp[p.x][p.y].step = dp[p.x][p.y].val = 0;
while(!q.empty())
{
p = q.front(); q.pop();
if(maps[p.x][p.y] == 'S')
{
if(anstep>dp[p.x][p.y].step||(anstep==dp[p.x][p.y].step&&ansnum<dp[p.x][p.y].val))
{
anstep=dp[p.x][p.y].step;
ansnum=dp[p.x][p.y].val;
}
}
for(int i = 0 ; i < 4 ; ++ i)
{
int x = p.x + fx[i][0];
int y = p.y + fx[i][1];
if(x>=0&&x<n&&y>=0&&y<m&&maps[x][y]!='#')
{
if(dp[x][y].step == -1)
{
q.push(Point(x,y));
dp[x][y].step = dp[p.x][p.y].step + 1;
}
if(dp[x][y].step == dp[p.x][p.y].step + 1)
{
dp[x][y].val = max(dp[p.x][p.y].val+value(x,y),dp[x][y].val);
}
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
for(int i = 0 ; i < n ; ++ i)
{
scanf("%s",maps[i]);
for(int j = 0 ; j < m ; ++ j)
{
if(maps[i][j]=='E')
{
p.x = i, p.y = j;
}
}
}
bfs();
if(ansnum == -1) printf("impossible\n");
else printf("%d %d\n",anstep,ansnum);
}
return 0;
}
E RP项链
题意:给你一个只有小写字母的字符串,长度为100000,再给你100个小写字符组合每个组合有两个小写字符(这个组合没有顺序,例如:给的ab,那么ab和ba都算这个组合。)。每个组合都有自己的价值,问你删除一些字符后使这个字符串包含的所有组合的价值和的最大值。例如: aaba 1 aa 1 answer: 2(去掉b后为aaa,有两个aa,价值为2.)。解法:DP(动态规划)。dp[j] 表示当前位置以这个字母结尾的所有串的最大价值。状态转移公式为:dp[j] = max(dp[j], dp[c]+ch[c][j]); dp[c]是前一位以c结尾的最大价值,ch[c][j]是c与j的组合的价值。需要考虑到更新值时前面是否出现过c,以及同字母组合需要先更新同字母组合。例如:
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
int dp[26];
int ch[26][26];
bool flag[26];
void init()
{
memset(dp, 0, sizeof dp);
memset(ch, 0, sizeof ch);
memset(flag, false, sizeof flag);
}
char s[100010];
int main()
{
//freopen("in","r",stdin);
//freopen("out","w",stdout);
while(~scanf("%s",s))
{
int n; scanf("%d",&n);
init();
while(n--)
{
char tmp[3]; int num;
scanf("%s%d",tmp,&num);
int a = tmp[0]-'a', b = tmp[1]-'a';
ch[b][a] = ch[a][b] = num;
}
flag[s[0]-'a'] = true;
int len = strlen(s);
for(int i = 1; i < len ; ++ i)
{
int c = s[i]-'a';
if(flag[c]) dp[c] += ch[c][c];
for(int j = 0 ; j < 26 ; ++ j)
{
if(!flag[j]) continue;
if(c!=j)
dp[c] = max(dp[c], dp[j] + ch[j][c]);
}
flag[c] = true;
}
int ans = 0;
for(int i = 0 ; i < 26 ; ++ i)
{
ans = max(ans, dp[i]);
}
printf("%d\n",ans);
}
return 0;
}