# 蓝桥杯之分治法与动态规划

[6.1 二分查找]

#include<cstdio>

int f(int a[],int x,int begin,int end){

if(begin+1==end) {
if(a[begin]>x) return begin;
return end;
}

int k=(begin+end)/2;
if(x>=a[k]){
return f(a,x,k,end);
}
return f(a,x,0,k);
}

int g(int a[],int x,int len){
if(x>a[len-1]) return -1;
return f(a,x,0,len);
}

int main(){
freopen("data.in","r",stdin);
int a[1000],i=0;

while(scanf("%d",&a[i++])!=EOF);

i--;
int r = g(a,32,i);
printf("%d",r);
}
--------------------------------------

[6.2 最大连续部分和]

2,4,-7,5,2,-1,2,-4,3

#include<cstdio>

int g(int a[],int begin,int end){

if(end==begin+1){
if(a[begin]>0) return a[begin]; else return 0;
}

int k=(begin+end)/2;

int t1=g(a,begin,k);
int t2=g(a,k,end);
int t3a=0;
int sum=0;
for(int i=k-1;i>=begin;i--){
sum+=a[i];
if(sum>t3a) t3a=sum;
}
int t3b=0;
sum=0;
for(int i=k;i<end;i++){
sum+=a[i];
if(sum>t3b) t3b=sum;
}

int t3=t3a+t3b;

int max=0;
if(t1>max) max=t1;
if(t2>max) max=t2;
if(t3>max) max=t3;

return max;
}

int main(){
freopen("data.in","r",stdin);
int a[1000],i=0;
while(scanf("%d,",&a[i++])!=EOF);

i--;
printf("%d",g(a,0,i));
}
--------------------------------------

[6.3 大数乘法]

multi("5935849584045839123456789","4595805849258430535")

--------------------------------------

#include <cstdio>
#include<map>

using namespace std;

map<int,int> m;

int fff(int n)
{
if (m.count(n)!=0)
return m[n];

int t=0;

if (n >= 1 && fff(n - 1) == 0)
t=1;
if (n >= 3 && fff(n - 3) == 0)
t=1;
if (n >= 7 && fff(n - 7) == 0)
t=1;
if (n >= 8 && fff(n - 8) == 0)
t=1;

if(t){
m[n]=1;
return 1;
}

return 0;
}

int main()
{
printf("55 : %s\n",  fff(55) ? "true" : "false");
}

#include<cstdio>

int g(int m, int n)
{
if (m == 1 || n == 1)
return 1;

return (g(m - 1, n) + g(m, n - 1)) % 10000;
}

int main()
{
int a[100][100]={0};

for(int i=1;i<100;i++){
a[i][1]=1;
a[1][i]=1;
}

for(int i=2;i<100;i++){
for(int j=2;j<100;j++){
a[i][j]=(a[i-1][j]+a[i][j-1])%10000;
}
}

printf("%d\n",a[20][15]);
printf("%d\n",g(20,15));
}

--------------------------------------

[6.4 缓存结果]

1缓存（按需存放）
2仔细设计计算次序，可以用数组

#include<cstdio>

int main(){
int a[10000]={0};
a[1]=1;
a[2]=1;

for(int i=3;i<10000;i++){
a[i]=(a[i-1]+a[i-2])%10000007;
}

int n;
scanf("%d",&n);

printf("%d\n",a[n]);

}
--------------------------------------

[6.5 动态规划]

X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图所示)

c e f d a b 是另一种合适的方案。

2

24

3

96

22

359635897

fb(n)  从边缘某格开始，到与它相邻的另一个边缘格子结束
fb(n) = fb(n-1) * 2

fa(n)  从某个边缘格子开始的所有情况
fa(n) = fb(n)      最后走对面格
+2*fa(n-1)     第1步走对面格
+4*fa(n-2) 第2步走对面格

fb(n)=fb(n-1)*2;

fa(n)=fb(i)*fa(n-i)*2+fb(n-i+1)*fa(i-1)*2

fa(i,n)=fb(i)*fa(n-i)*2+fb(n-i+1)*fa(i-1)*2

#include<cstdio>
#define M 1000000007

long long fb(int n){
if(n==1) return 1;
return fb(n-1)*2%M;
}

long long fa(int n){

if(n==1) return 1;
if(n==2) return 6;

return (fb(n)+fa(n-1)*2+fa(n-2)*4)%M;
}

long long fa(int i,int n){

return (fb(i)*fa(n-i)*2%M+fb(n-i+1)*fa(i-1)*2%M)*2%M;
}

long long g(int n){

if(n==1) return 2;
long long sum=0;
for(int i=2;i<n;i++){
sum=(fa(i,n)+sum)%M;
}
sum=(sum+4*fa(n))%M;
return sum;
}

int main(){
for(int i=1;i<130;i++){
int t=g(i);
printf("%d:%d\n",i,t);
}
} 

#include<cstdio>
#define M 1000000007

long long fa[1000]={0};
long long fb[1000]={0};

int f(){
fb[1]=1;
fb[2]=2;
fa[1]=1;
fa[2]=6;
for(int i=3;i<1000;i++){
fb[i]=fb[i-1]*2%M;
fa[i]=(fb[i]+fa[i-1]*2+fa[i-2]*4)%M;
}
}

long long g1(int n){

if(n==1) return 2;
long long sum=0;
for(int i=2;i<n;i++){
sum=((fb[i]*fa[n-i]*2%M+fb[n-i+1]*fa[i-1]*2%M)*2%M+sum)%M;
}
sum=(sum+4*fa[n])%M;
return sum;
}

int main(){
f();
for(int i=1;i<130;i++){
int t=g1(i);
printf("%d:%d\n",i,t);
}
} 
--------------------------------------

[6.6 作业]

#include<cstdio>
#define M 1000000007

long long g(int n){
if(n==1) return 3;
if(n==2) return 6;

return g(n-1)+2*g(n-2);
}

int main(){
long long a[1000];
a[1]=3;
a[2]=6;
for(int i=3;i<130;i++){
a[i]=a[i-1]+2*a[i-2]%M;
}

for(int i=1;i<130;i++){
//long long t=g(i);
long long t=a[i];
printf("%d:%lld\n",i,t);
}
}