1. 程式人生 > >洛谷P1311 選擇客棧

洛谷P1311 選擇客棧

esp for har 第一個 col truct 一個 amp %d

洛谷P1311 選擇客棧

時間復雜度O(N*K)
開兩個後綴和數組 a[ i ].color[ j ] 表示在i之後 (包括 i ) 有多少間 客棧是j 顏色的
以及 a[ i ].last 表示在i之後 (包括i ) 第一個小於等於 x 的 咖啡店的坐標

並且要特判一下 a[ i ].last == i 的情況 這是顏色相同的咖啡店數量要減一

 1 #include <cstdio>
 2 #define For(i,j,k) for(int i=j;i<=k;i++)
 3 #define LL long long 
 4
using namespace std ; 5 6 const int N = 200011 ; 7 struct node{ 8 int color[50],last,id ; 9 }a[N]; 10 int n,k,pos,alpha,num ; 11 LL sum ; 12 int color[N],money[N] ; 13 14 struct stack{ 15 int money,id ; 16 }st[N]; 17 18 inline int read() 19 { 20 int x = 0 , f = 1 ; 21 char
ch = getchar() ; 22 while(ch<0||ch>9) { if(ch==-) f = -1 ; ch = getchar(); } 23 while(ch>=0&&ch<=9) { x = x * 10+ch-48 ; ch = getchar(); } 24 return x * f ; 25 } 26 27 int main() 28 { 29 n = read() ; k = read() ; alpha = read() ; 30 For(i,1,n) {
31 color[ i ] = read() ; 32 money[ i ] = read() ; 33 } 34 for(int i=n;i>=1;i--) { 35 For(j,0,50) 36 a[ i ].color[ j ] = a[ i+1 ].color[ j ] ; 37 a[ i ].color[ color[i] ]++ ; 38 } 39 pos = n+1 ; 40 for(int i=n;i>=1;i--) { 41 if(money[ i ]<=alpha) pos = i ; 42 a[ i ].last = pos ; 43 } 44 For(i,1,n) { 45 pos = a[ i ].last ; 46 num = a[ pos ].color[ color[i] ] ; 47 if( pos==i ) num-- ; 48 sum = sum + num ; 49 } 50 printf("%lld\n",sum) ; 51 return 0 ; 52 }

考慮一個DP,第i個客棧的顏色為x,設f[i]表示i之前(不包括i)顏色為x能用的客棧的數量。
記一下c[x]表示顏色為x的最近的客棧,cnt[x]表示i之前(不包括i)所有顏色為x的客棧總數,
顯然c[x]之前的所有能用的客棧,仍然能與客棧i搭配,所以f[i]=f[c[x]];如果c[x]和i可以搭配,
那麽i之前所有的客棧全都可以用,所以f[i]=cnt[x],判斷的話就看最近的能用的咖啡館是不是在c[x]之後(含);
答案就是∑f[i]。這時候已經可以得滿分了,但是註意到f只與顏色有關,所以可以優化,代碼如下:

 1 #include<cstdio>
 2 int n,k,p,i,x,y,lst,f[51],cnt[51],c[51],ans;
 3 int main()
 4 {
 5     scanf("%d%d%d",&n,&k,&p);
 6     for(i=1;i<=n;++i)
 7     {
 8         scanf("%d%d",&x,&y);
 9         if(y<=p)
10             lst=i;
11         if(lst>=c[x])
12             f[x]=cnt[x];
13         ans+=f[x];
14         c[x]=i;
15         ++cnt[x];
16     }
17     printf("%d\n",ans);
18     return 0;
19 }

洛谷P1311 選擇客棧