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;
}