题目要求链接
分析
要注意审题,注意:这种数字在不重复利用每一位的条件下,可以提取出k(k>0)个子序列,而且保证提取出这k个子序列都是”233”,且不再剩余任何数字。当初我就是没有认真审题就导致花费了很长时间都没有做出来,后来又读了几遍题,才真正理解题意。
题意基本就是给出一个最大长度为1000的字符串,让你判断该字符串是否可以全部分解为233的子序列,且最后不在包含任何数字。
解题思路1:
从左向右循环考虑每一个2,由于我们是从左向右来考虑,因此最佳策略就是选择这个2之后最近的没有被配对的两个3与之配对,并将它们标记为已经配对。
最后再检查是否所有字符都被打上已配对的标记
我的代码
#include
#include
using namespace std;
bool a[1000]; //保存标记位
char c[1000]; //保存字符串
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
bool flag = true;
memset(a,0,sizeof(a));
scanf("%s",c);
int len = strlen(c);
/*从左向右循环考虑每一个2,由于我们是从左向右来考虑, 因此最佳策略就是选择这个2之后最近的没有被配对的两个3与之配对, 并将它们标记为已经配对。*/
for(int i=0; iint location1=-1,location2=-1;
if(c[i] == '2')
{
for(int j=i+1; jif(c[j]=='3' && a[j]==0)
{
if(location1 == -1)
{
location1 = j;
continue;
}
location2 = j;
a[i] = 1;
a[location1] = 1;
a[location2] = 1;
break;
}
}
}
}
//检查是否所有字符都被打上已配对的标记
for(int i=0; i//printf("%d\n",a[i]);
if(a[i]==0) flag = false;
}
if(flag){
printf("Yes\n");
}else{
printf("No\n");
}
}
return 0;
}
#include
#include
using namespace std;
char a[1000];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",a);
int len = strlen(a);
bool flag = true;
int cnt2 = 0, cnt3 = 0;
for(int i=0; iif(a[i] == '2')
{
cnt2++;
}else if(a[i] == '3')
{
if(cnt2 == 0)
{
flag = false;
break;
}
if(cnt3 == 1)
{
cnt2--;
cnt3 = 0;
}else{
cnt3++;
}
}else
{
flag = false;
break;
}
}
if(cnt2!=0 || cnt3!=0) flag = false;
if(flag){
printf("Yes\n");
}else{
printf("No\n");
}
}
return 0;
}
题目要求
分析
题意不太好理解,需要多读几遍。
其实题意就是让左右剑两两组合,使得组合中和的最大值尽可能小。那么可以想到,要使和的最大值尽可能小,那么必然是左剑的最小值和右剑的最大值组合,然后左剑的次小值和右剑的次大值组合,这样依次进行两两组合,那么这些和中最大的值就是我们所要求的答案。
如果左手剑的数值是a[1,2,3,…,n] , 右手剑的数值是b[1,2,3…,n]。我们显然可以想到,先把两个数组a[],b[]排序,然依次将a[i]和b[n-i-1]求和,最后max{a[i]+b[n-i-1]}就是所求的值。且不说排序所要花费的时间,单单是对1-n时,数据比较n次,时间复杂度就是O(N^2)。而N是1e5级别的,N^2就是1e10。一般来说,1e8运算所需要的时间是1秒钟,这样显然会超时。
那么该怎么办呢?注意分析题,我们可以发现,剑的值不超过100,所以可以用100大小左右数组记录每一个值存在多少把剑,左手从小到大,右手从大到小,不断交替减掉匹配的次数,更新当前匹配的最大值。基本就是一种桶排序的思想。
我的代码
//#include
#include
#include
using namespace std;
//left[i]表示左手剑中攻击力值为i的个数。right[j]表示右手剑中攻击力值为j的个数
int left[101],right[101];
int main()
{
int N;
while(~scanf("%d",&N))
{
if(N == 0) break;
//memset函数给int类型数组赋值只能赋为-1或0,因为 该函数是逐字节赋值的
memset(left,0,sizeof(left));
memset(right,0,sizeof(right));
int x,y;
for(int k=1; k<=N; k++)
{
scanf("%d%d",&x,&y);
left[x]++; right[y]++;
int maxSum = 0;
int match = 0;
int location1 = 1, location2 = 100;
int cishu1 = left[location1], cishu2 = right[location2];
while(match != k)
{
if(cishu1 == 0)
{
cishu1 = left[++location1];
continue;
}
if(cishu2 == 0)
{
cishu2 = right[--location2];
continue;
}
if(location1+location2 > maxSum )
{
maxSum = location1+location2;
}
if(cishu1 == cishu2)
{
match += cishu1;
cishu1 = left[++location1];
cishu2 = right[--location2];
}else if(cishu1 < cishu2)
{
match += cishu1;
cishu2 -= cishu1;
cishu1 = left[++location1];
}else if(cishu1 > cishu2)
{
match += cishu2;
cishu1 -= cishu2;
cishu2 = right[--location2];
}
}
printf("%d\n",maxSum);
}
printf("\n");
}
}
我的代码这里把#include
注释掉了,换成了#include
是因为iostream中已经定义过了left和right。而cstdio头文件中没有。
#include
#include
#include
using namespace std;
const int LEN = 13;
queue<string> GJ;
queue<string> XS;
string a[LEN]; //a[]保存桌面上的牌
int main()
{
int T;
cin>>T;
int N1,N2,K;
string c;
//初始化a[]
for(int i=0; i"0"; //"0"表示什么都没有
}
while(T--)
{
//读入数据,并放到相应的队列中
cin>>N1; //scanf("%d",&N1);
for(int i=0; icin>>c; //scanf("%s",&c[0]);
GJ.push(c);
}
cin>>N2; //scanf("%d",&N2);
for(int i=0; icin>>c; //scanf("%s",&c[0]);
XS.push(c);
}
//进行K次放牌
scanf("%d",&K);
for(int i=0; iif(i%2 == 0)
{
c = GJ.front(); GJ.pop();
for(int j=0; j//找到了相同的牌
if(c == a[j])
{
for(int k=j; k"0"; k++)
{
GJ.push(a[k]);
a[k] = "0";
}
GJ.push(c);
break;
}
//没有找到相同的牌
if(a[j] == "0")
{
a[j] = c;
break;
}
}
}else{
c = XS.front(); XS.pop();
for(int j=0; j//找到了相同的牌
if(c == a[j])
{
for(int k=j; k"0"; k++)
{
XS.push(a[k]);
a[k] = "0";
}
XS.push(c);
break;
}
//没有找到相同的牌
if(a[j] == "0")
{
a[j] = c;
break;
}
}
}
}
//输出,同时顺便清空GJ、XS、a[]中的牌
cout<<"Deck:"; //printf("Deck:");
for(int i=0; i"0"; i++)
{
cout<<" "<//printf(" %s",a[i]);
a[i] = "0";
}
cout<//printf("\n");
cout<<"GJ:"; //printf("GJ:");
while(!GJ.empty())
{
cout<<" "<//printf(" %s",GJ.front());
GJ.pop();
}
cout<//printf("\n");
cout<<"XS:"; //printf("XS:");
while(!XS.empty())
{
cout<<" "<//printf(" %s",XS.front());
XS.pop();
}
cout<//printf("\n");
cout<// printf("\n");
}
return 0;
}
我用scanf和printf输入输出字符串有问题。。一直搞不懂问题出在哪儿。。
题目评价:
考查内容:基本数据结构的使用
时间复杂度:O(n)
题目难度:☆ ☆
我的体会
就这三道题,其实都不难,但比赛的时候我只做出来一道,而且是自己错了好几次才做出来。
我觉得首先要认真读题,除了要真正理解题目的意思,还要注意一些数据的范围,经常是这些范围限定了不能用哪些方法来解题。
其次我慢慢觉得代码风格也要注意,首先要尽可能精简准确,能一句话表达清楚的绝不用三五行,不要写得太过冗长,但同时不容易理解的地方也要写注释。写注释不仅可以给别人看的时候会好些,更重要的是可以帮助自己理清思路,知道自己每一步要做什么。精简和注释并不矛盾。