A题:
http://acm.hdu.edu.cn/showproblem.php?pid=1412
这题盼神说要用链表,但蛋疼的是我用链表出现上次组队赛中的编译错误,连续三次无解,于是果断使用STL中的链表,这也算是使用了链表吧,哈哈!
STL乃神器也,不解释!
#include <stdio.h> #include <list> #include <string.h> using namespace std; int main() { int n,m,a[10005],b[10005],i,j; while(~scanf("%d%d",&n,&m)) { for(i = 0; i<n; i++) scanf("%d",&a[i]); for(i = 0; i<m; i++) scanf("%d",&b[i]); list<int> la; list<int> lb; for(i = 0; i<n; i++) la.push_back(a[i]); for(i = 0; i<m; i++) lb.push_back(b[i]); la.merge(lb); la.sort(); la.unique();//先排序才能去重,否则不行 int cnt = 0; while(!la.empty()) { if(!cnt) printf("%d",la.front()); else printf(" %d",la.front()); cnt++; la.pop_front(); } printf("\n"); } return 0; }
B题
http://acm.hdu.edu.cn/showproblem.php?pid=1443
题意:给出一个k,代表有K个好人与K个坏人,其中前K个是好人,后K个是坏人,根据约瑟夫环游戏的原理,在坏人都出局而好人没有一个出局的情况下,m最小是多大
思路:由于k的数值小,直接暴力枚举打表
#include <stdio.h> #include <string.h> int main() { int n,a[30],i,j,MIN,jose[14]; for(i = 1;i<14;i++) { n = 2*i; memset(a,0,sizeof(a)); MIN = 1; for(j = 1;j<=i;j++) { a[j]=(a[j-1]+MIN-1)%(n-j+1);//(a[j-1]+MIN-1)计算的是从现在这个人的位置开始数能到达的人的位置,(n-j+1)是出局人后一个人的位置,因为要由他开始数,得到的是下个出局的人的位置,注意这个位置是从0开始的 if(a[j]<i)//好人出局了,j重置,min增加进行枚举 { j = 0; MIN++; } } jose[i] = MIN; } while(~scanf("%d",&n),n) { printf("%d\n",jose[n]); } return 0; }
C题
http://acm.hdu.edu.cn/showproblem.php?pid=3336
题意:给以字符串 计算出以前i个字符为前缀的字符中 在主串中出现的次数和
如: num(abab)=num(a)+num(ab)+num(aba)+num(abab)=2+2+1+1=6;
题解:next[i]记录的是长度为i 不为自身的最大首尾重复子串长度 num[i]记录长度为next[i]的前缀所重复出现的次数
#include <stdio.h> #include <string.h> using namespace std; #define MAXN 200005 #define MOD 10007 int next[MAXN],sum[MAXN],n; char str[MAXN]; void getnext()//kmp的next数组,不解释 { int i = 0,j = -1; next[0] = -1; while(str[i]) { if(j == -1 || str[i] == str[j]) { ++i; ++j; next[i] = j; } else j = next[j]; } } int main() { int t,ans; scanf("%d",&t); while(t--) { getchar(); scanf("%d",&n); ans = 0; memset(sum,0,sizeof(sum)); scanf("%s",str); getnext(); for(int i = 1; i<=n; i++) sum[next[i]] = (sum[next[i]]+1)%MOD; for(int i = 1; i<=n; i++) ans=(ans+sum[i]+1)%MOD; printf("%d\n",ans); } return 0; }
D题
http://acm.hdu.edu.cn/showproblem.php?pid=1022
题意:给出进站与出栈的顺序,看能否顺利出站
思路:再一次STL,估计也就我这种没节操的在用STL做了吧?嘎嘎,再一次证明STL的神奇
#include <stdio.h> #include <stack> #include <string.h> using namespace std; int main() { stack<int> S; int n,i,j,k; int flag[1000]; char in[1000],out[1000]; while(~scanf("%d",&n)) { scanf("%s%s",in,out); i = j = k = 0; while(i<n && j<n+1) { if(!S.empty() && S.top() == out[i])//如果栈顶元素与现在出站的车号相等 { i++; flag[k] = 1; k++; S.pop();//删除栈顶元素 } else { S.push(in[j]); flag[k] = 0; j++; k++; } } if(k!=2*n)//k没有计算2*n次的话,肯定不符合 { printf("No.\n"); } else { printf("Yes.\n"); for(i = 0;i<k;i++) { if(flag[i]) printf("out\n"); else printf("in\n"); } } printf("FINISH\n"); } return 0; }
E题
http://acm.hdu.edu.cn/showproblem.php?pid=3328
题意:其实这题并不难,只是题意有点难理解
首先给出每张牌的初始状态,U为面朝上,D为面朝下,然后跟着几个操作,L代表从左边翻,R代表从右边翻
例如第一个样例,前两个R,代表最右边的5翻转,叠放到4上,然后这两张叠放的一起翻转,叠放到3上
剩下的两个L,代表最左边的1翻转,叠峰到2上,然后这两张再一起翻转,叠放到3,4,5形成的堆上,然后他们就成为了一堆
最后给出n询问,询问这一堆的第几张牌是什么状态
例如Card 1 is a face down 2.就是说这个堆的第一张牌是面朝下的2
思路:知道题意就可以直接开始模拟了
#include <stdio.h> #include <string.h> using namespace std; struct node { int face,num; }card[105][105]; int ip[105],work[105]; void turn(int x,int y) { int i; for(i=ip[x];i>=1;i--) { if(card[x][i].face)//翻转的过程 card[x][i].face = 0; else card[x][i].face = 1; card[y][++ip[y]] = card[x][i];//二维数组记录堆的状况 } } int main() { int cas = 1; int n,m,i,j; char str[105],done[105]; while(~scanf("%d",&n),n) { scanf("%s%s",str,done); memset(ip,0,sizeof(ip)); for(i = 0;i<n;i++) { card[i+1][1].num = i+1; if(str[i] == 'U') card[i+1][1].face = 1; else card[i+1][1].face = 0; ip[i+1] = 1; } int l = 1,r = n; for(i = 0;i<n-1;i++)//翻转过程 { if(done[i] == 'R') { turn(r,r-1); r--; } else { turn(l,l+1); l++; } } scanf("%d",&m); for(i = 1;i<=m;i++) { scanf("%d",&work[i]); } printf("Pile %d\n",cas++); for(i = 1;i<=m;i++) { if(card[r][n-work[i]+1].face==1)//这里和r都是可以的,因为最后他们必然叠放在同一堆,l=r printf("Card %d is a face up %d.\n",work[i],card[r][n-work[i]+1].num); else printf("Card %d is a face down %d.\n",work[i],card[r][n-work[i]+1].num); } } return 0; }
F题
http://acm.hdu.edu.cn/showproblem.php?pid=1870
题意:上次比赛就出过了,我就不解释了
思路:我用STL我骄傲
#include <stdio.h> #include <stack> #include <string.h> using namespace std; int main() { stack<char> S; char str[1005]; int i,j,len,cnt; while(gets(str)) { while(!S.empty()) S.pop(); len = strlen(str); cnt = i = 0; while(i<len) { if(str[i]=='(') { S.push(str[i]); i++; cnt++; } else { if(str[i]==')') { S.pop(); cnt--; i++; } else break; } } if(!S.empty()) printf("%d\n",cnt); } return 0; }
G题
http://acm.hdu.edu.cn/showproblem.php?pid=1702
题意:FIFO-先进先出,明显是队列
FILO-先进后出,这就是栈
IN就是往栈或者队列里末尾插入一个数字
OUT就是显示出队列或者出栈的元素
思路:赤裸裸的STL
#include <stdio.h> #include <queue> #include <stack> #include <string.h> using namespace std; void que(int n) { queue<int> Q; char s[10]; int a; while(n--) { scanf("%s",s); if(!strcmp(s,"IN")) { scanf("%d",&a); Q.push(a); } else { if(Q.empty()) printf("None\n"); else { printf("%d\n",Q.front()); Q.pop(); } } } } void sta(int n) { stack<int> S; char s[10]; int a; while(n--) { scanf("%s",s); if(!strcmp(s,"IN")) { scanf("%d",&a); S.push(a); } else { if(S.empty()) printf("None\n"); else { printf("%d\n",S.top()); S.pop(); } } } } int main() { int n,t; char str[100]; scanf("%d",&t); while(t--) { scanf("%d%s",&n,str); if(!strcmp(str,"FIFO")) que(n); else if(!strcmp(str,"FILO")) sta(n); } return 0; }
H题
http://acm.hdu.edu.cn/showproblem.php?pid=4414
题意:找出十字架的个数,要注意十字架旁边不能有#
思路:直接模拟
这题早在盼神开的专题中就有了,然后盼神唠叨的说,这道没人做,要出来做比赛题,于是我果断上午就做了,然后下午果断就出现了,然后果断就A了,没节操啊没节操
#include <stdio.h> #include <string.h> char map[55][55]; int main() { int n,i,j,k,ans,flag; while(~scanf("%d",&n),n) { ans = 0; for(i = 0; i<n; i++) scanf("%s",map[i]); int cnt1,cnt2,cnt3,cnt4; for(i=1; i<n-1; i++) { for(j=1; j<n-1; j++) { flag=1; if(map[i][j]=='#')//这个#是中间的 { cnt1=cnt2=cnt3=cnt4=0; for(k=i-1; k>=0; k--)//向上找 { if(map[k][j]=='#') { if(map[k][j-1]=='#'||map[k][j+1]=='#')//每找一个看这个的上下是否有#,有则不是要求的十字架 { flag=0; break; } cnt1++;//统计向上伸长的长度 } else break; } if(cnt1<1) flag=0;//由于十字架长度要最少为3,所以小于1肯定不行 for(k=i+1; k<n&&flag; k++)//下向 { if(map[k][j]=='#') { if(map[k][j-1]=='#'||map[k][j+1]=='#') { flag=0; break; } cnt2++; } else break; } if(cnt1!=cnt2) flag=0;//上下不等,肯定不是十字架 for(k=j-1; k>=0&&flag; k--)//左向 { if(map[i][k]=='#') { if(map[i-1][k]=='#'||map[i+1][k]=='#') { flag=0; break; } cnt3++; } else break; } if(cnt3<1) flag=0; for(k=j+1; k<n&&flag; k++)//右向 { if(map[i][k]=='#') { if(map[i-1][k]=='#'||map[i+1][k]=='#') { flag=0; break; } cnt4++; } else break; } if(cnt3!=cnt4) flag=0; if(flag) ans++;//所有条件符合,个数加1 } } } printf("%d\n",ans); } return 0; }
总的来说,这次的题目还是挺水的= =