您的位置:首页 > 其它

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

2017-07-12 09:31 155 查看

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

2017-07-12 09:31
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

#include<cstdio>  
#include<cstring>  
using namespace std;  
int f[22][1005],a[22],n,k;  
int main()  
{  
    memset(f,0,sizeof f);  
    scanf("%d%d",&n,&k);  
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);  
    for(int i=1;i<=n;i++)for(int j=0;j<=k;j++)  
    {  
    if(j>a[i])f[i][j]=f[i-1][j]+f[i-1][j-a[i]];  
        else if(j==a[i])f[i][j]=f[i-1][j]+1;  
        else f[i][j]=f[i-1][j];  
    }  
    printf("%d\n",f
[k]);  
    return 0;  
}  

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

#include<cstdio>  
#include<algorithm>  
#include<cstring>  
using namespace std;  
const int maxn=5005;  
struct Node{int x;int y;}node[maxn];  
bool cmp(Node a,Node b)  
{  
    if(a.x<b.x)return 1;  
    else if(a.x==b.x&&a.y<b.y)return 1;  
    else return 0;  
}  
int main()  
{  
    int n,f[maxn],maxx=-1;  
    scanf("%d",&n);  
    for(int i=1;i<=n;i++)scanf("%d%d",&node[i].x,&node[i].y);  
    sort(node+1,node+1+n,cmp);  
    for(int i=0;i<maxn;i++)f[i]=1;  
    for(int i=2;i<=n;i++)for(int j=i-1;j>=1;j--)  
    if(node[i].y<node[j].y)f[i]=max(f[i],f[j]+1);  
    for(int i=1;i<=n;i++)if(f[i]>maxx)maxx=f[i];printf("%d\n",maxx);  
    return 0;  
}  

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

#include<cstdio>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
const int maxn=100010;  
char s[maxn][12];  
struct node  
{  
    node*next[26];//26个子节点的指针  
    int code;//对应的序号,中间节点或空节点为-1  
    node(){code=-1;for(int i=0;i<26;i++)next[i]=NULL;}  
}head;//Trie的单个节点  
void insert(char *s,int v)//插入操作  
{  
    node *now=&head;//从根节点开始  
    for(int i=0;i<strlen(s);i++)  
    {  
        if(now->next[s[i]-'a']==NULL)now->next[s[i]-'a']=new node;//如果节点不存在,创建一个新节点  
        now=now->next[s[i]-'a'];//遍历到下一个节点  
    }  
    now->code=v;//给叶子节点存储信息  
}  
int query(char *s)//查询操作  
{  
    node*now=&head;  
    for(int i=0;i<strlen(s);i++)  
    {  
        if(now->next[s[i]-'a']!=NULL)now=now->next[s[i]-'a'];//如果节点存在,继续遍历  
        else return -1;//如果节点不存在,返回-1  
    }  
    return now->code;//返回叶子节点的值  
}  
int main()  
{  
    memset(s,0,sizeof s);  
    int cur=0;char a[12],q[12];  
    while(1)  
    {  
        scanf("%s",s[cur++]);  
        char c=getchar();  
        if(c=='\n')break;  
        scanf("%s",a);  
        insert(a,cur-1);  
    }  
    if(query(s[cur-1])==-1)printf("eh\n");  
    else printf("%s\n",s[query(s[cur-1])]);//输入非常麻烦  
    while(scanf("%s",q)==1)  
    {  
        if(query(q)==-1)printf("eh\n");  
        else printf("%s\n",s[query(q)]);  
    }  
    return 0;  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: