http://acm.hdu.edu.cn/showproblem.php?pid=4545
hdu 4545 魔法串
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 237 Accepted Submission(s): 96
Problem Description
小明和他的好朋友小西在玩一个新的游戏,由小西给出一个由小写字母构成的字符串,小明给出另一个比小西更长的字符串,也由小写字母组成,如果能通过魔法转换使小明的串和小西的变成同一个,那么他们两个人都会很开心。这里魔法指的是小明的串可以任意删掉某个字符,或者把某些字符对照字符变化表变化。如:
小西的串是 abba;
小明的串是 addba;
字符变化表 d b (表示d能转换成b)。
那么小明可以通过删掉第一个d,然后将第二个d转换成b将串变成abba。
现在请你帮忙判断:他们能不能通过魔法转换使两个人的串变成一样呢?
小西的串是 abba;
小明的串是 addba;
字符变化表 d b (表示d能转换成b)。
那么小明可以通过删掉第一个d,然后将第二个d转换成b将串变成abba。
现在请你帮忙判断:他们能不能通过魔法转换使两个人的串变成一样呢?
Input
首先输入T,表示总共有T组测试数据(T <= 40)。
接下来共T组数据,每组数据第一行输入小西的字符串,第二行输入小明的字符串(数据保证字符串长度不超过1000,小明的串的长度大于等于小西的,且所有字符均为小写字母)。接着输入字母表,先输入m,表示有m个字符变换方式(m< = 100),接着m行每行输入两个小写字母,表示前一个可以变为后一个(但并不代表后一个能变成前一个)。
接下来共T组数据,每组数据第一行输入小西的字符串,第二行输入小明的字符串(数据保证字符串长度不超过1000,小明的串的长度大于等于小西的,且所有字符均为小写字母)。接着输入字母表,先输入m,表示有m个字符变换方式(m< = 100),接着m行每行输入两个小写字母,表示前一个可以变为后一个(但并不代表后一个能变成前一个)。
Output
对于每组数据,先输出Case数。
如果可以通过魔法转换使两个人的串变成一样,输出“happy”,
否则输出“unhappy”。
每组数据占一行,具体输出格式参见样例。
如果可以通过魔法转换使两个人的串变成一样,输出“happy”,
否则输出“unhappy”。
每组数据占一行,具体输出格式参见样例。
Sample Input
2 abba addba 1 d b a dd 0
Sample Output
Case #1: happy Case #2: unhappy
#include<cstdio>
#include<cstring>
const int N=10002;
char s1[N],s2[N];
bool g[26][26];
int l1,l2;
int main(){
int i,j,T,m,ca=1;
char u[3],v[3];
scanf("%d",&T);
while(T--){
scanf("%s%s",s1,s2);
l1=strlen(s1),l2=strlen(s2);
scanf("%d",&m);
memset(g,0,sizeof(g));
while(m--){
scanf("%s%s",u,v);
g[u[0]-'a'][v[0]-'a']=1;
}
for(i=0,j=0;i<l1&&j<l2;j++){
int p=s1[i]-'a',q=s2[j]-'a';
if(s2[j]==s1[i]||g[q][p])i++;
}
printf("Case #%d: ",ca++);
puts(i==l1?"happy":"unhappy");
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=4546
hdu 4546比赛难度
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 199 Accepted Submission(s): 35
Problem Description
最近,小明出了一些ACM编程题,决定在HDOJ举行一场公开赛。
假设题目的数量一共是n道,这些题目的难度被评级为一个不超过1000的非负整数,并且一场比赛至少需要一个题,而这场比赛的难度,就是所有题目的难度之和,同时,我们认为一场比赛与本场题目的顺序无关,而且题目也不会重复。
显而易见,很容易得到如下信息:
假设比赛只用1个题目,有n种方案;
假设比赛使用2个题目,有(n-1)*n/2种方案;
假设比赛使用3个题目,有(n-2)*(n-1)*n/6种方案;
............
假设比赛使用全部的n个题目,此时方案只有1种。
经过简单估算,小明发现总方案数几乎是一个天文数字!
为了简化问题,现在小明只想知道在所有的方案里面第m小的方案,它的比赛难度是多少呢?
假设题目的数量一共是n道,这些题目的难度被评级为一个不超过1000的非负整数,并且一场比赛至少需要一个题,而这场比赛的难度,就是所有题目的难度之和,同时,我们认为一场比赛与本场题目的顺序无关,而且题目也不会重复。
显而易见,很容易得到如下信息:
假设比赛只用1个题目,有n种方案;
假设比赛使用2个题目,有(n-1)*n/2种方案;
假设比赛使用3个题目,有(n-2)*(n-1)*n/6种方案;
............
假设比赛使用全部的n个题目,此时方案只有1种。
经过简单估算,小明发现总方案数几乎是一个天文数字!
为了简化问题,现在小明只想知道在所有的方案里面第m小的方案,它的比赛难度是多少呢?
Input
输入数据的第一行为一个整数T(1 <= T <= 20),表示有T组测试数据。
每组测试数据第一行为两个整数n, m(0 < n, m <= 10000),表示现在有n个题目,现在要求第m小的方案的比赛难度。接下来第二行有n个数字,分别表示这n个题目的难度值。
每组测试数据第一行为两个整数n, m(0 < n, m <= 10000),表示现在有n个题目,现在要求第m小的方案的比赛难度。接下来第二行有n个数字,分别表示这n个题目的难度值。
Output
对于每组测试数据,输出一行"Case #c: ans"(不包含引号),ans 表示要求的第m小的比赛难度,输入数据保证存在第m小的方案,具体参见样例。
Sample Input
2 5 6 1 1 1 1 1 5 25 1 2 3 4 5
Sample Output
Case #1: 2 Case #2: 11
分析:multiset直接搞,保存当前前K个数
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
multiset<int> S,tmp;
multiset<int>::iterator it,it1;
const int N=10002;
int a[N];
int main(){
int T,i,n,k,ca=1,t1,t2;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
S.clear();
for(i=0;i<n;i++)scanf("%d",a+i);
sort(a,a+n);
bool f=0;
S.insert(0);
for(i=0;i<n;i++){
if(f){
it1=S.end(),it1--;tmp.clear();
for(it=S.begin();it!=S.end();it++,it1--){
t1=(*it),t2=(*it1);
if(a[i]+t1<t2)tmp.insert(a[i]+t1),S.erase(S.find(t2));
else break;
}
for(it=tmp.begin();it!=tmp.end();it++)S.insert((*it));
}else{
tmp.clear();
for(it=S.begin();it!=S.end();it++)tmp.insert(a[i]+(*it));
for(it=tmp.begin();it!=tmp.end();it++)S.insert((*it));
if(S.size()>=k+1)f=1;
while(S.size()>k+1){
it=S.end();it--;
S.erase(it);
}
}
}
it=S.end(),it--;
printf("Case #%d: %d\n",ca++,(*it));
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=4547
hdu 4547 CD操作
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 166 Accepted Submission(s): 48
Problem Description
在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
Input
输入数据第一行包含一个整数T(T<=20),表示样例个数;
每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
Output
请输出每次询问的结果,每个查询的输出占一行。
Sample Input
2 3 1 B A C A B C 3 2 B A C B A C C A
Sample Output
2 1 2
分析:LCA模版题
#include<cstdio>
#include<cstring>
#include<map>
#include<string>
#include<vector>
using namespace std;
const int N=100002;
vector<int> g[N];
map<string,int> m1;
int lv[N],root;
int p[N][15],S[15];
bool vis[N],in[N];
int max(int a,int b){return a>b?a:b;}
int dfs(int u,int fa,int deep){
int res=deep,i,v;
p[u][0]=fa;
lv[u]=deep;
vis[u]=1;
for(i=0;i<g[u].size();i++){
v=g[u][i];
if(!vis[v])res=max(res,dfs(v,u,deep+1));
}
return res;
}
void init(int n){
int i,j,level;
for(S[0]=i=1;i<15;i++)S[i]=S[i-1]<<1;
memset(vis,0,sizeof(vis));
memset(p,-1,sizeof(p));
level=dfs(root,-1,1);
for(i=1;S[i]<=level;i++)for(j=1;j<=n;j++){
if(p[j][i-1]!=-1)p[j][i]=p[p[j][i-1]][i-1];
}
}
int LCA(int x,int y){
if(lv[x]<lv[y])x^=y,y^=x,x^=y;
int i,log;
for(log=0;S[log]<=lv[x];log++);
for(i=--log;i>=0;i--)if(lv[x]-S[i]>=lv[y])x=p[x][i];
if(x==y)return x;
for(i=log;i>=0;i--){
if(p[x][i]!=-1&&p[x][i]!=p[y][i])x=p[x][i],y=p[y][i];
}
return p[x][0];
}
int main(){
int n,m,ca=1,i,cnt,a,b,c,T,ans;
char st[42],ed[42];
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
cnt=0;m1.clear();
for(i=0;i<n;i++)g[i].clear();
for(i=1;i<n;i++){
scanf("%s%s",st,ed);
if(!m1[st])m1[st]=++cnt;
if(!m1[ed])m1[ed]=++cnt;
a=m1[st]-1,b=m1[ed]-1;
g[b].push_back(a);
in[a]=1;
}
for(i=0;i<n;i++)if(!in[i]){root=i;break;}
init(n);
while(m--){
scanf("%s%s",st,ed);
a=m1[st]-1,b=m1[ed]-1;
c=LCA(a,b);
ans=lv[a]-lv[c];
if(c!=b)ans++;
printf("%d\n",ans);
}
}
return 0;
}