题目
407:Heritage
描述
Your rich uncle died recently, and the heritage needs to be divided among your relatives and the church (your uncle insisted in his will that the church must get something). There are N relatives (N <= 18) that were mentioned in the will. They are sorted in descending order according to their importance (the first one is the most important). Since you are the computer scientist in the family, your relatives asked you to help them. They need help, because there are some blanks in the will left to be filled. Here is how the will looks:
Relative #1 will get 1 / … of the whole heritage,
Relative #2 will get 1 / … of the whole heritage,
---------------------- …
Relative #n will get 1 / … of the whole heritage.
The logical desire of the relatives is to fill the blanks in such way that the uncle’s will is preserved (i.e the fractions are non-ascending and the church gets something) and the amount of heritage left for the church is minimized.
输入
The only line of input contains the single integer N (1 <= N <= 18).
输出
Output the numbers that the blanks need to be filled (on separate lines), so that the heritage left for the church is minimized.
样例输入
2
样例输出
2
3
翻译
各种读,还是不太理解。
大概意思是有遗产,分给家人,还要有一部分给教堂。不是平均分配,要从头到尾倒序分配,先多后少。后来找到题解后,才知道
Relative #1 will get 1 / … of the whole heritage,
很重要。填空是填到这个省略号的地方。可能跟the heritage needs to be divided among your relatives and the church有关,divided也许不能仅仅理解为分配!
理解
第一个人分1/2(拿走1/2,剩1/2)
第二个人分1/3(2*(2-1)+1,是不是理解为从剩的1/2拿走2/3=1/3,剩1/6)
第三个人分1/7(3*(3-1)+1,是不是理解为从剩的1/6拿走2/3=1/9,剩1/6/3=1/12,但是这个结果跟答案不一样,推测错误)
第四个人分1/43(7*(7-1)+1,后面的推测没得到验证)
第i个人分1/(i*(i-1)+1)。
这样问题就是递推,第一个人分2,第二个人分3,第三个人分7,第i个人分i*(i-1)+1,就算这个就行了。
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
到18时得有100005位
问题的难点就是长整数计算。
问题
(i*(i-1)+1)
希望有能力的朋友能讲下为什么一定是d[i+1]=d[i]*(d[i]-1)+1。非常感谢
代码
#include <bits/stdc++.h>
using namespace std;
int n;
string d[20]={“0”,“2”,“3”};
void view(){
for(int i=1;i<=n;i++)cout<<d[i]<<endl;
}
string suan(string a,string b){
int m=b.length()-1;
while(b[m]==‘0’&&m>=0){//如果尾数是零,全改成9
b[m–]=‘9’;
}
if(m>=0)b[m]=(b[m]-‘1’)+‘0’;//直到不是零,减去1
int d[100005];//结果存整型数组,长度没仔细研究,200位都会错
memset(d,0,sizeof(d));
int dm=0;
string c=“”;
for(int i=a.length()-1;i>=0;i–)//被乘数和乘数都是从个位开始计算,从最右边往左边
for(int j=b.length()-1;j>=0;j–){
int ad=a[i]-‘0’,bd=b[j]-‘0’,
ix=a.length()-1-i,jx=b.length()-1-j;//跟被乘数位置是相反的,个位计算在0位,往高位可以延展
d[ix+jx]+=adbd;//被乘数和乘数位数的和是乘积的位数
dm=max(dm,i+j);//记住长度
}
d[0]+=1;//d[i+1]=d[i](d[i]-1)+1,完成+1部分
for(int i=0;d[i]>0||i<=dm;i++){//遍历每一位,个位在零位最左边
if(d[i]>9)d[i+1]+=d[i]/10,d[i]%=10;//如果>9进位
c=char(d[i]+‘0’)+c;//结果存到字符串中,高位在左边
if(i>dm)dm++;//长度可以不变
}
return c;
}
int main(){
//freopen(“in.cpp”,“r”,stdin);
cin>>n;
for(int i=3;i<=n;i++)
d[i]=suan(d[i-1],d[i-1]);
//d[i]=d[i-1]*(d[i-1]-1)+1;
view();
return 0;
}
总结
大整数乘法多做几遍就熟练了,就是需要坐得住,仔细考虑并解决各个环节。
尤其是被乘数乘数个位在右边高位,但是计算结果个位在左边低位0位,是挺有意思的。
还得要提高英语阅读理解能力,同样的单词,读不到真意思。