1. 程式人生 > 實用技巧 >南陽ccpc C題 The Battle of Chibi 樹狀陣列+dp

南陽ccpc C題 The Battle of Chibi 樹狀陣列+dp

題目:

Cao Cao made up a big army and was going to invade the whole South China. Yu Zhou was worried about it. He thought the only way to beat Cao Cao is to have a spy in Cao Cao's army. But all generals and soldiers of Cao Cao were loyal, it's impossible to convince any of them to betray Cao Cao.

So there is only one way left for Yu Zhou, send someone to fake surrender Cao Cao. Gai Huang was selected for this important mission. However, Cao Cao was not easy to believe others, so Gai Huang must leak some important information to Cao Cao before surrendering.

Yu Zhou discussed with Gai Huang and worked outNNinformation to be leaked, in happening order. Each of the information was estimated to hasaiaivalue in Cao Cao's opinion.

Actually, if you leak information with strict increasing value could accelerate making Cao Cao believe you. So Gai Huang decided to leak exact
MMinformation with strict increasing value in happening order. In other words, Gai Huang will not change the order of theNNinformation and just selectMMof them. Find out how many ways Gai Huang could do this.

InputThe first line of the input gives the number of test cases,T(1100)T(1≤100).TTtest cases follow.


Each test case begins with two numbersN(1N103)N(1≤N≤103)andM(1MN)M(1≤M≤N), indicating the number of information and number of information Gai Huang will select. ThenNNnumbers in a line, theithithnumberai(1ai109)ai(1≤ai≤109)indicates the value in Cao Cao's opinion of theithithinformation in happening order.OutputFor each test case, output one line containingCase #x: y, wherexxis the test case number (starting from 1) andyyis the ways Gai Huang can select the information.

The result is too large, and you need to output the result mod by1000000007(109+7)1000000007(109+7).
Sample Input

2
3 2
1 2 3
3 2
3 2 1

Sample Output

Case #1: 3
Case #2: 0

        
 

Hint

In the first cases, Gai Huang need to leak 2 information out of 3. He could leak any 2 information as all the information value are in increasing order. 
In the second cases, Gai Huang has no choice as selecting any 2 information is not in increasing order.

題意:

給你n個有序的數,問你能找到多少個m長度的嚴格遞增子序列

題解:

我們設dp[i][j]表示:截至於第i個數(使用了第i個數),所能構成的嚴格遞增子序列長度為j的個數為dp[i][j]

那麼dp[i][j]的值肯定是:dp[k][j-1]之和,k屬於[1,i-1]。且要滿足,那麼輸入的第k個數要小於第i個數才可以加上dp[k][j-1]

我們看資料n=1e3,如果暴力去寫,複雜度就是O(n3),所以我們肯定需要優化(我那時也不知道咋弄)

看其他題解發現,使用樹狀陣列來優化,但是樹狀陣列求得字首和,而我們只是需要字首和的一部分,這可怎麼辦。。

然後我們就可以處理一下輸入,對於第k個數不小於第i個數的,我們可以先不處理它,那麼這個dp[k][j-1]就是0

那麼我們的字首和相當於沒有加上它,就可以達到滿足我們的需要。這個處理只需要一個排序就可以

程式碼:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<queue>
 5 #include<map>
 6 #include<vector>
 7 #include<cstring>
 8 using namespace std;
 9 const int mod=1e9+7;
10 const int maxn=1e3+5;
11 #define mem(a) memset(a,0,sizeof(a))
12 //求sum(dp[1-x][j])
13 int n,m,dp[maxn][maxn];
14 struct shudui
15 {
16     int id,val;
17 }que[maxn];
18 bool cmp(shudui x,shudui y)
19 {
20     if(x.val!=y.val)
21         return x.val<y.val;
22     return x.id>y.id; //如果兩個val相等,因為題目要求嚴格遞增,所以這樣排序就可以滿足題意
23 }
24 int lowbit(int x)
25 {
26     return x&(-x);
27 }
28 void update(int x,int y,int val)  //更新包含dp[x][y]的
29 {   //字尾陣列項
30     while(x<=n)
31     {
32         dp[x][y]=(dp[x][y]+val)%mod;
33         x+=lowbit(x);
34     }
35 }
36 int get_sum(int x,int y)
37 {
38     int sum=0;
39     while(x>0)
40     {
41         sum=(sum+dp[x][y])%mod;
42         x-=lowbit(x);
43     }
44     return sum;
45 }
46 int main()
47 {
48     int t,p=0;
49     scanf("%d",&t);
50     while(t--)
51     {
52         mem(dp);
53         scanf("%d%d",&n,&m);
54         for(int i=1;i<=n;++i)
55         {
56             scanf("%d",&que[i].val);
57             que[i].id=i;
58         }
59         sort(que+1,que+1+n,cmp);
60         for(int i=1;i<=n;++i)
61         {
62             for(int j=1;j<=m;++j)
63             {
64                 if(j==1)
65                     update(que[i].id,j,1);
66                 else //因為我們按照val排過序了,所以我們可以加上字首和就行
67                 {
68                     int sum=get_sum(que[i].id-1,j-1);
69                     update(que[i].id,j,sum);
70                 }
71             }
72         }
73         printf("Case #%d: %d\n",++p,get_sum(n,m));
74     }
75     return 0;
76 }