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

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

代码:

#include
#include
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[n][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的不上升子序列的个数

#include
#include
#include
using namespace std;
const int maxn=5005;
struct Node{int x;int y;}node[maxn];
bool cmp(Node a,Node b)
{
    if(a.x=1;j--)
    if(node[i].ymaxx)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)

具体实现如下:

#include
#include
#include
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;inext[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;inext[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;
}

你可能感兴趣的:(HFOI2017.07.11校内赛(普及组)题解)