HFOI2017.07.11校内赛(普及组)题解

来源:互联网 发布:软件什么是架构 编辑:程序博客网 时间:2024/05/29 10:09

HFOI2017.07.11校内赛(普及组)题解

7人阅读 评论(0)收藏举报
1:数字组合
描述
    有n个正整数,找出其中和为t(t也是正整数)的可能的组合方式。如:
    n=5,5个数分别为1,2,3,4,5,t=5;
    那么可能的组合有5=1+4和5=2+3和5=5三种组合方式。
输入
    输入的第一行是两个正整数n和t,用空格隔开,其中1<=n<=20,表示正整数的个数,t为要求的和(1<=t<=1000)
    接下来的一行是n个正整数,用空格隔开。
输出
    和为t的不同的组合方式的数目。
样例输入
    5 5
    1 2 3 4 5
样例输出

    3

令a(i)表示第i个正整数,f(i,j)表示前i个数,可以组成数字j的组数,则状态转移方程为:

if(j>a[i])f[i][j]=f[i-1][j]+f[i-1][j-a[i]];
if(j==a[i])f[i][j]=f[i-1][j]+1;
if(j<a[i])f[i][j]=f[i-1][j];

代码:

[cpp] view plain copy
  1. #include<cstdio>  
  2. #include<cstring>  
  3. using namespace std;  
  4. int f[22][1005],a[22],n,k;  
  5. int main()  
  6. {  
  7.     memset(f,0,sizeof f);  
  8.     scanf("%d%d",&n,&k);  
  9.     for(int i=1;i<=n;i++)scanf("%d",&a[i]);  
  10.     for(int i=1;i<=n;i++)for(int j=0;j<=k;j++)  
  11.     {  
  12.     if(j>a[i])f[i][j]=f[i-1][j]+f[i-1][j-a[i]];  
  13.         else if(j==a[i])f[i][j]=f[i-1][j]+1;  
  14.         else f[i][j]=f[i-1][j];  
  15.     }  
  16.     printf("%d\n",f[n][k]);  
  17.     return 0;  
  18. }  

T2:木棍加工
题目描述
一堆木头棍子共有n根,每根棍子的长度和宽度都是已知的。棍子可以被一台机器一个接一个地加工。机器处理一根棍子之前需要准备时间。准备时间是这样定义的:
第一根棍子的准备时间为1分钟;
如果刚处理完长度为L,宽度为W的棍子,那么如果下一个棍子长度为Li,宽度为Wi,并且满足L>=Li,W>=Wi,这个棍子就不需要准备时间,否则需要1分钟的准备时间;
计算处理完n根棍子所需要的最短准备时间。比如,你有5根棍子,长度和宽度分别为(4, 9),(5, 2),(2, 1),(3, 5),(1, 4),最短准备时间为2(按(4, 9)、(3, 5)、(1, 4)、(5, 2)、(2, 1)的次序进行加工)。
输入输出格式
输入格式:
第一行是一个整数n(n<=5000),第2行是2n个整数,分别是L1,W1,L2,w2,…,Ln,Wn。L和W的值均不超过10000,相邻两数之间用空格分开。
输出格式:
仅一行,一个整数,所需要的最短准备时间。
输入输出样例
输入样例#1:
5
4 9 5 2 2 1 3 5 1 4
输出样例#1:
2

dailworth定理:一个序列的不上升子序列的个数等于最长上升子序列的个数(自己想一想也能明白)

【有请zxj大神帮我们证明一下】

然后题目就转变为一个简单的DP问题了。

先对l进行排序,然后求r的不上升子序列的个数

[cpp] view plain copy
  1. #include<cstdio>  
  2. #include<algorithm>  
  3. #include<cstring>  
  4. using namespace std;  
  5. const int maxn=5005;  
  6. struct Node{int x;int y;}node[maxn];  
  7. bool cmp(Node a,Node b)  
  8. {  
  9.     if(a.x<b.x)return 1;  
  10.     else if(a.x==b.x&&a.y<b.y)return 1;  
  11.     else return 0;  
  12. }  
  13. int main()  
  14. {  
  15.     int n,f[maxn],maxx=-1;  
  16.     scanf("%d",&n);  
  17.     for(int i=1;i<=n;i++)scanf("%d%d",&node[i].x,&node[i].y);  
  18.     sort(node+1,node+1+n,cmp);  
  19.     for(int i=0;i<maxn;i++)f[i]=1;  
  20.     for(int i=2;i<=n;i++)for(int j=i-1;j>=1;j--)  
  21.     if(node[i].y<node[j].y)f[i]=max(f[i],f[j]+1);  
  22.     for(int i=1;i<=n;i++)if(f[i]>maxx)maxx=f[i];printf("%d\n",maxx);  
  23.     return 0;  
  24. }  

3:词典
描述
    你旅游到了一个国外的城市。那里的人们说的外国语言你不能理解。不过幸运的是,你有一本词典可以帮助你。
输入
    首先输入一个词典,词典中包含不超过100000个词条,每个词条占据一行。每一个词条包括一个英文单词和一个外语单词,两个单词之间用一个空格隔开。而且在词典中不会有某个外语单词出现超过两次。词典之后是一个空行,然后给出一个由外语单词组成的文档,文档不超过100000行,而且每行只包括一个外语单词。输入中出现单词只包括小写字母,而且长度不会超过10。
输出
    在输出中,你需要把输入文档翻译成英文,每行输出一个英文单词。如果某个外语单词不在词典中,就把这个单词翻译成“eh”。
样例输入
    dog ogday
    cat atcay
    pig igpay
    froot ootfray
    loops oopslay

    atcay
    ittenkay
    oopslay
样例输出
    cat
    eh
    loops
提示
    输入比较大,推荐使用C语言的I / O函数。
来源
    翻译自Waterloo local 2001.09.22的试题 

很显然是Trie的题目(典型的用空间换时间)

好吧map也可以过(膜拜大神wzr)

具体实现如下:

[cpp] view plain copy
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<algorithm>  
  4. using namespace std;  
  5. const int maxn=100010;  
  6. char s[maxn][12];  
  7. struct node  
  8. {  
  9.     node*next[26];//26个子节点的指针  
  10.     int code;//对应的序号,中间节点或空节点为-1  
  11.     node(){code=-1;for(int i=0;i<26;i++)next[i]=NULL;}  
  12. }head;//Trie的单个节点  
  13. void insert(char *s,int v)//插入操作  
  14. {  
  15.     node *now=&head;//从根节点开始  
  16.     for(int i=0;i<strlen(s);i++)  
  17.     {  
  18.         if(now->next[s[i]-'a']==NULL)now->next[s[i]-'a']=new node;//如果节点不存在,创建一个新节点  
  19.         now=now->next[s[i]-'a'];//遍历到下一个节点  
  20.     }  
  21.     now->code=v;//给叶子节点存储信息  
  22. }  
  23. int query(char *s)//查询操作  
  24. {  
  25.     node*now=&head;  
  26.     for(int i=0;i<strlen(s);i++)  
  27.     {  
  28.         if(now->next[s[i]-'a']!=NULL)now=now->next[s[i]-'a'];//如果节点存在,继续遍历  
  29.         else return -1;//如果节点不存在,返回-1  
  30.     }  
  31.     return now->code;//返回叶子节点的值  
  32. }  
  33. int main()  
  34. {  
  35.     memset(s,0,sizeof s);  
  36.     int cur=0;char a[12],q[12];  
  37.     while(1)  
  38.     {  
  39.         scanf("%s",s[cur++]);  
  40.         char c=getchar();  
  41.         if(c=='\n')break;  
  42.         scanf("%s",a);  
  43.         insert(a,cur-1);  
  44.     }  
  45.     if(query(s[cur-1])==-1)printf("eh\n");  
  46.     else printf("%s\n",s[query(s[cur-1])]);//输入非常麻烦  
  47.     while(scanf("%s",q)==1)  
  48.     {  
  49.         if(query(q)==-1)printf("eh\n");  
  50.         else printf("%s\n",s[query(q)]);  
  51.     }  
  52.     return 0;