每组输入包括一个整数:N(1<=N<=1000000)。
对于每组数据,输出f(n)%1000000000。
7
6
#include<stdio.h>
#include<math.h>
#include<vector>
using namespace std;
vector<int> v;
int dp[1000001];
const int mod=1000000000;
int main(){
int i,j,N;
for(i=0;i<=20;i++) v.push_back((int)pow(2,i));
for(j=0;j<=1000000;j++) dp[j]=1;
for(i=1;i<=20;i++)
for(j=1;j<=1000000;j++)
if(j>=v[i])
dp[j]=(dp[j]+dp[j-v[i]])%mod;
while(scanf("%d",&N)!=EOF)
printf("%d\n",dp[N]);
}//背包问题 提前把表打好 #include <iostream>
using namespace std;
int main(){
int a[21];
a[0]=1;
for(int i=1;i<=20;i++)a[i]=a[i-1]*2;
int b[1000001];
b[0]=1;
for(int i=0;i<=20;i++)
{
for(int j=a[i];j<=1000000;j++)
{
b[j]+=b[j-a[i]];
if(b[j]>=1000000000)b[j]%=1000000000;
}
}
int c=0;
while(cin>>c)cout<<b[c]<<endl;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
long long dp[maxn+5];
int n;
void getDP()
{
dp[0] = 1;
for(int i = 1;i <= maxn; i++)
{
if(i & 1) dp[i] = dp[i-1] % 1000000000;
else dp[i] = (dp[i-1]+dp[i/2]) % 1000000000;
}
}
int main()
{
ios::sync_with_stdio(false);
getDP();
while(cin >> n)
{
cout << dp[n] << '\n';
}
return 0;
} //递推公式 n=1时 1种方式 n=2时(f[n]=2)2种方式 n=3时 2种方式 n=4时4种方式
// n为奇数是f[n]=f[n-1] n为偶数时f[n]=f[n-1]+f[n/2]
#include<stdio.h>
int main()
{//实际上在自己本地编辑器里面f[1000000]会出现错误,[]太大了,但是提交是没有问题的
int n,i;
int f[1000000];//n实际做f的下标,数组值作为方法个数
scanf("%d",&n);
f[1]=1;//n=1时只有一种方式
for(i=2;i<=n;i++)//f的下标
{
if(i%2==0)//偶数
f[i]=(f[i/2]+f[i-1])%1000000000;
else//奇数
f[i]=f[i-1]%1000000000;
}
printf("%d",f[n]);
return 0;
}
#include <iostream>
#define MAXSIZE 1000001
using namespace std;
int get_num_of_div(int n){ //复杂度过高不通过
if(n==1)
return 1;
if(n%2!=0)
return get_num_of_div(n-1);
else
return get_num_of_div(n-1)+get_num_of_div(n/2);
}
void init(int div[]){
}
int main(){
int div[MAXSIZE];//辅助数组减轻时间复杂度。以后递推关系要么递归要么用数组把所有可能都算出来先
int n;
div[0]=div[1]=1;
for(int i=2;i<MAXSIZE;i++){
if(i%2==0)
div[i]=(div[i-1]+div[i/2])%1000000000;
else
div[i]=div[i-1];
}
while(cin>>n){
cout << div[n] << endl;
}
} 把百度到的思路整理一下~
1.对于给定的整数,可以分奇偶讨论:
①N为奇,每个划分必含有1。
②N为偶,划分分为两类:S=A并B。其中任意a属于A,a含1;任意b属于B,b不含1。
2.设Sn为输入为n时的划分的全集,|Sn|表示划分的个数,则
①n为奇,Sn每个划分去掉1可以得到Sn-1,即|Sn-1|=|Sn|。
②n为偶,A每个划分去掉1可以得到Sn-1,即|A|=|Sn-1|;
B每个划分除以2可以得到Sn/2,即|B|=|Sn/2|。
③S1=1.
有上面讨论可得程序: #include<iostream>搬运一下思路: 记f(n)为n的划分数,我们有递推公式:f(2m + 1) = f(2m), f(2m) = f(2m - 1) + f(m), 初始条件:f(1) = 1。
证明:
证明的要点是考虑划分中是否有1。
记: A(n) = n的所有划分组成的集合, B(n) = n的所有含有1的划分组成的集合, C(n) = n的所有不含1的划分组成的集合, 则有: A(n) = B(n)∪C(n)。
又记: f(n) = A(n)中元素的个数, g(n) = B(n)中元素的个数, h(n) = C(n)中元素的个数, 易知: f(n) = g(n) + h(n)。
以上记号的具体例子见文末。
我们先来证明: f(2m + 1) = f(2m), 首先,2m + 1 的每个划分中至少有一个1,去掉这个1,就得到 2m 的一个划分,故 f(2m + 1)≤f(2m)。 其次,2m 的每个划分加上个1,就构成了 2m + 1 的一个划分,故 f(2m)≤f(2m + 1)。 综上,f(2m + 1) = f(2m)。
接着我们要证明: f(2m) = f(2m - 1) + f(m), 把 B(2m) 中的划分中的1去掉一个,就得到 A(2m - 1) 中的一个划分,故 g(2m)≤f(2m - 1)。 把 A(2m - 1) 中的划分加上一个1,就得到 B(2m) 中的一个划分,故 f(2m - 1)≤g(2m)。 综上,g(2m) = f(2m - 1)。
把 C(2m) 中的划分的元素都除以2,就得到 A(m) 中的一个划分,故 h(2m)≤f(m)。 把 A(m) 中的划分的元素都乘2,就得到 C(2m) 中的一个划分,故 f(m)≤h(2m)。 综上,h(2m) = f(m)。
所以: f(2m) = g(2m) + h(2m) = f(2m - 1) + f(m)。
这就证明了我们的递推公式。
#include<iostream> #define MAXSIZE 1000001 using namespace std; int main(){ int n; int result[MAXSIZE]; result[0] = result[1] = 1; for(int i = 2; i<MAXSIZE; ++i){ if(i%2 == 0){ result[i] = (result[i-1] + result[i/2])%1000000000; } else{ result[i] = result[i-1]%1000000000; } } while(scanf("%d",&n) != EOF) cout<<result[n]<<endl; return 0; }
/*这道题确实可以用动态规划来解,它其实是一个完全背包求恰装满背包时的方案总数
问题.具体是,因为每一个拆分必须是1,2,4,2^3,...2^19(考虑n最大为10^6),
所以对于一个整数n,看它的这种拆分数有多少个,就相当于现在有20种物品,第i种物品
的花费是2^(i-1),每一种可以重复取, dp[i][j]表示前i种物品恰装满容量为j的物品时
的方案总数,从而dp[i][j] = dp[i-1][j] + dp[i][j-a[i]]
*/
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib> //rand ( ), srand ( )
#include <ctime> //time ( )
using namespace std;
int n, dp[1000002], a[21];
int main ( )
{
int i, j, t;
for ( i = 1; i <= 20; i ++ )
a[i] = ( 1 << ( i - 1) );
dp[0] = 1;
while ( cin >> n )
{
memset ( dp + 1, 0, sizeof ( dp ) );
for ( i = 1; i <= 20; i ++ )
{
for ( j = a[i]; j <= n; j ++ )
{
dp[j] += dp[j - a[i]];
dp[j] %= 1000000000;
}
}
cout << dp[n] << endl;
}
return 0;
}
#include<iostream>
using namespace std;
int dp[1000001];
long f2n(long n)
{
for(long i=1;i<=n;i++)
{
if(i==1)dp[i]=1;
else if(i%2)dp[i]=dp[i-1];
else dp[i]=(dp[i-1]+dp[i/2])%1000000000;
}
return dp[n];
}
int main()
{
int n;
while(cin>>n){
cout<<f2n(n)<<endl;
}
return 0;
}
#include<iostream>
using namespace std;
int dp[1000001];
long f2n(long n)
{
for(long i=1;i<=n;i++)
{
if(i==1)dp[i]=1;
else if(i%2)dp[i]=dp[i-1];
else dp[i]=(dp[i-1]+dp[i/2])%1000000000;
}
return dp[n];
}
int main()
{
int n;
while(cin>>n){
cout<<f2n(n)<<endl;
}
return 0;
}
dp[i]表示f(i)
状态转移方程
i是奇数:dp[i]=dp[i-1]
i是偶数:dp[i]=dp[i-1]+dp[i/2] 其中dp[i-1]表示拆分有1的种数,dp[i/2]表示拆分没有1的种数
#include <iostream>
#include <vector>
using namespace std;
/*
思路:
1、奇数:f(5)的分解方法为f(4) + 1,1不可再分,f(n) = f(n - 1)
2、偶数:f(4)的分解方法为2 + 1 + 1或2 + 2, f(n) = f(n - 2) + f(n / 2)
*/
int main() {
long long n;
while (cin >> n) {
vector<long long> nums(n + 1);
nums[1] = 1;
nums[2] = 2;
for (int i = 3; i <= n; i++) {
if (i % 2 == 1) {
nums[i] = nums[i - 1] % 1000000000;
}
else {
nums[i] = (nums[i - 2] + nums[i / 2]) % 1000000000;
}
}
cout << nums[n] << endl;
}
return 0;
}
#include<iostream>
using namespace std;
int f(int n)//递推关系,递归实现复杂度太高
{
if(n == 1)
return 1;
if(n % 2 == 1)
return f(n - 1);
else
return f(n - 1) + f( n / 2);
}
int ff(int n)
{
int *array = new int[n+1];
array[1] = 1;
array[2] = 2;
for(int i = 3; i <= n; i++)
{
if(i % 2 == 1)
array[i] = array[i-1] % 1000000000;
else
array[i] = (array[i-1] + array[i/2]) % 1000000000;
}
return array[n];
}
int main()
{
int num;
cin >> num;
cout << ff(num) << endl;
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
while (cin >> n) {
vector<int>dp(n + 1);
dp[0] = 1;
for (int i = 1; i <= n; i++) {
if (i % 2 == 0)
dp[i] = (dp[i - 1] + dp[i / 2]) % 1000000000;
else
dp[i] = dp[i - 1] % 1000000000;
}
cout << dp[n] << endl;
}
return 0;
} 有两种情况
n是奇数,必定可以拆出一个1,不管其他的部分怎么变,这个1不会改变,也就是说这个1不会影响拆分的结果,即
dp[i]=dp[i-1]
n是偶数,拆分的结果只有两种情况,要么带有1的形式,要么不带1的形式(全是偶数)
奇拆分(带有1的形式):dp[i-1] 原因同上
偶拆分(全是偶数的形式):dp[i/2]
dp[8] 4+4 2+2+4 2+2+2+2
dp[4] 2+2 1+1+2 1+1+1+1
可以发现dp[8]的偶拆分刚好是dp[4]所有拆分情况的2倍形式
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
int[] dp = new int[1000001];
dp[1] = 1;
for (int i = 2; i <= 1000000; i++) {
if (i % 2 == 0) {
dp[i] = (dp[i / 2] + dp[i - 1]) % 1000000000;
} else {
dp[i] = dp[i - 1];
}
}
while ((s = br.readLine()) != null) {
int n = Integer.parseInt(s);
System.out.println(dp[n]);
}
}
}