A.Eleven(水题)
/**
题目翻译:给出一个N,输出一个N个字符组成的名字。
第i个字符是斐波那契数则输出'O',其他情况均输出小
'o'。
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
int vis[1005];
void fun() {
memset(vis,0,sizeof(vis));
int num1 = 1;
int num2 = 1;
vis[1] = 1;
for(int i = 3; i <= 16; i++) {
int temp = num1+num2;
vis[temp] = 1;
num2 = num1;
num1 = temp;
}
}
int main() {
fun();
int N;
while(~scanf("%d",&N)) {
for(int i = 1; i <= N; i++) {
if(vis[i]) {
printf("O");
}
else {
printf("o");
}
}
printf("\n");
}
return 0;
}
B.Radio Station (水题)
/**
题目翻译:这个题目让作的工作非常像计算机网络中的DNS,
域名解析服务器的工作的逆过程(因为DNS是根据域名找IP地址,
而本题是根据IP找相应名字)。给出N个服务器的名字和IP地址,
服务器名字可能有相同的,但是IP地址是唯一的,然后给出M个
名字和IP,找IP对应的服务器的名字。
题目中N和M都高达1000,直接查找比对时间复杂度1000*1000,
不会有什么问题,如果可以借助二分查找,则会更快一些。
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <algorithm>
using namespace std;
struct infor {
char name[15];
char ip[30];
}a[1200];
bool cmp(infor b,infor c) {
if(strcmp(b.ip,c.ip)<0) {
return true;
}
return false;
}
int binarySearch(int left,int right,char value[]) {
int mid;
while(left<=right) {
mid = (left+right)/2;
if(strcmp(value,a[mid].ip) == 0) {
return mid;
}
else if(strcmp(value,a[mid].ip) > 0) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
return -1;
}
int main() {
int N,M;
while(~scanf("%d%d",&N,&M)) {
for(int i = 0; i < N; i++) {
scanf("%s%s",a[i].name,a[i].ip);
}
sort(a,a+N,cmp);
char name[15],ip[30];
while(M--) {
scanf("%s%s",name,ip);
int len = strlen(ip);
ip[len-1] = '\0';
int pos = binarySearch(0,N-1,ip);
printf("%s %s; #%s\n",name,ip,a[pos].name);
}
}
return 0;
}
C.The Monster(思维:区间枚举+模拟)
/**
题目翻译:给出一个字符串,只由'(' ')' '?'三种字符构成。
题目规定括号匹配的序列是合法序列,对于给定字符串中的?
它可以代表'('或')',问给出的字符串中有多少个合法的子串。
解题思路:比赛的时候,觉得每个问号两种状态,以为是个DP,
写了半天没写出来,后来看别人的题解,是一个模拟题目。思路
枚举所有区间,起初把所有遇到的?当作右括号处理。
match用来表示当前匹配状态,cnt被当作右括号的问号个数。
(1)当前字符是'(':match++
(2)当前字符是')':match--
(3)当前字符是'?':match--;cnt++
在此过程中只要出现match为0,代表当前区间匹配。
当match<0,则说明当前序列是右括号开头,则需要看之前还
有没有被当作右括号的问号,如果存在,则把其中一个变成
左括号,让序列重新以左括号开头,如果不存在,则以右括号
开头的序列永远不可能匹配,可以直接结束。
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <algorithm>
using namespace std;
char str[10002];
int main() {
while(~scanf("%s",str)) {
int match,ans,cnt;
ans = 0;
int len = strlen(str);
for(int i = 0; i < len; i++) {
match = cnt = 0;
for(int j = i; j < len; j++) {
if(str[j] == '(') {
match++;
}
else if(str[j] == ')') {
match--;
}
else { //问号先按')'处理
match--;
cnt++;
}
//区间合法
if(match == 0) {
ans++;
}
//出现右括号开头的情况
if(match < 0) {
if(cnt){ //还存在当作')'的问好,把它变成左括号。
cnt--;
match = 1;
}
else {
break;
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
D.MADMAX(难题:博弈+DP+记忆化搜索)
/**
题目翻译:给出一个N个顶点,M条边的有向无环图。每条边上
都有一个字符(小写字母)。Max和Lucas一起玩游戏,Max先手,
Lucas后手,然后他们选择各自初始顶点开始游戏,两个人轮流
沿着图中的边走,如果某条边可走当且仅当该边上的字符大于等于
上一次对手走过边的字符。最后谁先无法前进谁输。根据初始两人
所处的不同位置判断两个人的输赢情况,Max赢输出A,否则输出B。
解题思路:
DP + 记忆化搜索。
dp[x][y][z] 代表先手在x,后手在y,字符为z的时候,先手是输是赢。
如果先手赢,dp[x][y][z]=1,否则dp[x][y][z] = 0.
对于x能走的一条边,假如该边通向u,字符为ch,假如x走该边,则看
dp[y][u][ch]的值。
(1)dp[y][u][ch] = 1.则x走该边输,则不走该边继续考虑走别的边。
(2)dp[y][u][ch] = 0.则x走该边赢,则dp[x][y][z] = 1.
只有x所有的出边走了后都会输,则x必输。由于两人游戏均选择最优策略。
则只要x有一条出边使它赢,则x必赢。
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <queue>
using namespace std;
const int maxn = 102;
int Map[maxn][maxn]; //存放地图
int N,M;
int dp[maxn][maxn][26];
void init() {
for(int i = 1; i <= N;i++) {
for(int j = 1; j <= N; j++) {
Map[i][j] = -1;
}
}
memset(dp,-1,sizeof(dp));
}
int dfs(int x,int y,int z) {
if(dp[x][y][z] != -1)
return dp[x][y][z];
dp[x][y][z] = 0;
for(int i = 1; i <= N; i++) {
if(Map[x][i] >= z) {
if(dfs(y,i,Map[x][i])==0){
dp[x][y][z] = 1;
break;
}
}
}
return dp[x][y][z];
}
int main() {
while(~scanf("%d%d",&N,&M)) {
init(); //初始化地图。
int u,v;
char ch;
for(int i = 0; i < M; i++) {
scanf("%d%d %c",&u,&v,&ch);
Map[u][v] = ch-'a';
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= N; j++) {
if(dfs(i,j,0)) {
printf("A");
}
else {
printf("B");
}
}
printf("\n");
}
}
return 0;
}