洛谷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 ",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 ",ans); 18 return 0; 19 }