训练赛6(2014上海全国邀请赛——题目重现 )
导语
区域赛邀请赛练习,知道自己菜,所以挑一些看起来能做的做一做,整理一下
涉及的知识点
思维、dp
题目
A(HDU 5090)
题目大意:有N个盒子,每个盒子有初始球的数量,给出一个数字K,对每个盒子可以额外添加K个球或者不加球,进行多次操作后,如果最后能使得将盒子按照球数量升序排序,并且第i个盒子对应的个数就是i,则Jerry胜利,反之Tom胜利,判断谁胜利,多组样例
思路:开一个桶记录每个数字出现的个数,然后遍历1~N的桶,如果某个值为空,就回溯,看看该值-t*K是否存在多的个数,存在,则说明当前值可以被转换,不存在,则代表该值无法得到
代码
#include <bits/stdc++.h>
using namespace std;
int K,N,bucket[121],M;//开桶
int main() {
scanf("%d",&M);
while(M--) {
bool flag=0;
scanf("%d%d",&N,&K);
for(int i=0; i<N; i++) {
int t;
scanf("%d",&t);
bucket[t]++;
}
for(int i=1; i<=N; i++) {
if(bucket[i]==0) {
if(i<=K) {
printf("Tom\n");
flag=1;
break;
}//小于K的值无法没转换出来
for(int j=i-K; j>=1; j-=K)
if(bucket[j]) {//可以转换
bucket[j]--;
bucket[i]++;
break;
}
if(bucket[i]==0) {//没有转换的值
printf("Tom\n");
flag=1;
break;
}
bucket[i]--;//清空
} else
bucket[i]--;//清空
}
if(!flag)
printf("Jerry\n");
memset(bucket,0,sizeof(bucket));
}
return 0;
}
C(HDU 5092)
题目大意:给出一个N*M的矩阵,求出一条从第一行到最后一行的累和最小且最右的通路,从上到下输出通路通过点的列数,只要相邻都可以走(对角也可),但不能往上一层走
思路:直接对每个位置进行DP,当前位置选择从左上,上,右上取最优解,完成DP后回溯
代码
#include <bits/stdc++.h>
using namespace std;
int Photo[121][121],n,m,T,dp[121][121];
int main() {
scanf("%d",&T);
for(int p=1; p<=T; p++) {
stack<int>S;
int minn=INT_MAX,pos=0;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%d",&Photo[i][j]);//扫描
for(int i=1; i<=n; i++)
dp[i][0]=dp[i][m+1]=Photo[i][0]=Photo[i][m+1]=INT_MAX;//预处理边界值
for(int i=0; i<=m+1; i++)
dp[1][i]=Photo[1][i];//同上
for(int i=2; i<=n; i++)
for(int j=1; j<=m; j++)
dp[i][j]=Photo[i][j]+min(min(dp[i-1][j],dp[i-1][j-1]),dp[i-1][j+1]);
//dp过程
printf("Case %d\n",p);
for(int i=1; i<=m; i++)
if(dp[n][i]<=minn) {
minn=dp[n][i];
pos=i;
}//获取最值
S.push(pos);
for(int i=n; i>=2; i--) {//回溯
int t=S.top();
if(dp[i][t]==dp[i-1][t+1]+Photo[i][t])
S.push(t+1);
else if(dp[i][t]==dp[i-1][t]+Photo[i][t])
S.push(t);
else
S.push(t-1);
}
while(S.size()!=1) {
printf("%d ",S.top());
S.pop();
}
printf("%d\n",S.top());
S.pop();
memset(dp,0,sizeof(dp));
memset(Photo,0,sizeof(Photo));
}
return 0;
}
J(HDU 5099)
题目大意:给出两个字符串,分成三个部分:A部分(1字符)、B部分(1字符)、C部分(4字符),比较A部分大小和BC部分大小,规则如下:A部分按照字典序比较,B+C部分,如果B相同,比较C部分,不同则比较C的前三位,按照字典序
思路:直接模拟
代码
#include <bits/stdc++.h>
using namespace std;
int T;
int main() {
scanf("%d",&T);
for(int i=1; i<=T; i++) {
string a,b;
cin >>a>>b;
printf("Case %d:",i);
int lena=a.length(),lenb=b.length();
if(a[0]>b[0])
printf(" >");
else if(a[0]==b[0])
printf(" =");
else
printf(" <");
if(a[1]==b[1]) {
a=a.substr(2,lena-2);
b=b.substr(2,lenb-2);
if(a>b)
printf(" >");
else if(a==b)
printf(" =");
else
printf(" <");
} else {
a=a.substr(2,lena-3);
b=b.substr(2,lenb-3);
if(a>b)
printf(" >");
else if(a==b)
printf(" =");
else
printf(" <");
}
putchar('\n');
}
return 0;
}
参考文献
无