題目連結:http://www.lydsy.com/JudgeOnline/problem.php?id=1600
題意:
給你一個長度為n的木板,讓你把這個木板切割成四段(長度為整數),並且要求這四段可以構成一個四邊形。
問你有多少種切割方法(切割點不同就算不同)。
題解:
構成四邊形的條件:
任意一邊長度 < 周長/2
證明:設四邊為a,b,c,d。因為有a < b+c+d,所以2*a < a+b+c+d = C,所以a < C/2。
簡化問題:
給你n個小木塊,排成一排。問你將這些小木塊分成四部分,且能構成四邊形的方案數。
表示狀態:
dp[i][j] = combinations
i:已經選了前i個木塊
j:已經分成了j部分
找出答案:
ans = dp[n][4]
第n塊已經選了,共被分成了4部分。
如何轉移:
dp[i][j] = ∑ dp[i-k][j-1] (k <= i, k < (n+1)/2)
同時保證下標 >= 0,以及邊長k < 周長/2。
邊界條件:
dp[0][0] = 1
others = 0
什麼都沒選為一種方案。
優化:
字首和。
(其實不優化也能過。。。)
AC Code:
1 // state expression: 2 // dp[i][j] = combinations 3 // i: considering ith board 4 // 5 // find the answer: 6 // ans = dp[n][4] 7 // 8 // transferring: 9 // dp[i][j] = sigma dp[i-k][j-1] 10 // k: 1 to min(half,i) 11 // 12 // boundary: 13 // dp[0][0] = 1 14 // others = 0 15 #include <iostream> 16 #include <stdio.h> 17 #include <string.h> 18 #define MAX_N 2505 19 20 using namespace std; 21 22 int n; 23 int dp[MAX_N][5]; 24 int sum[MAX_N][5]; 25 26 void read() 27 { 28 cin>>n; 29 } 30 31 int cal_sum(int x,int y,int k) 32 { 33 if(x==0) return sum[y][k]; 34 return sum[y][k]-sum[x-1][k]; 35 } 36 37 void update_sum(int x,int y) 38 { 39 if(x==0) sum[x][y]=dp[x][y]; 40 else sum[x][y]=sum[x-1][y]+dp[x][y]; 41 } 42 43 void solve() 44 { 45 memset(dp,0,sizeof(dp)); 46 dp[0][0]=1; 47 for(int i=0;i<=n;i++) 48 { 49 sum[i][0]=1; 50 } 51 for(int j=1;j<=4;j++) 52 { 53 for(int i=1;i<=n;i++) 54 { 55 dp[i][j]=cal_sum(max(0,i-(n+1)/2+1),i-1,j-1); 56 update_sum(i,j); 57 } 58 } 59 } 60 61 void print() 62 { 63 cout<<dp[n][4]<<endl; 64 } 65 66 int main() 67 { 68 read(); 69 solve(); 70 print(); 71 }