昨天做了牛客小白竞赛的题目,发现我果然™是个小白 连小白也不如 。现在把会的题目放一下
把不严格非递减的序列改成严格非递减的最小代价,很明显,就是要求最大不下降子序列(下简称LIS,尽管它们的意义不完全相同)的长度,并用字符串长度减去这个长度即可
#include <cstdio>
#include <algorithm>
#include <cstring>
const int M=1000001;
using namespace std;
char s[M];
int lis(char *s,int n) {
if(n==0) return 0;
if(n==1) return 1;
static int dp[M];
int res=1;
fill(dp,dp+n+1,1);
for(int i=1;i<n;i++) {
for(int j=0;j<i;j++) {
if(s[i]>=s[j]) {
dp[i]=max(dp[i],dp[j]+1);
res=max(res,dp[i]);
}
}
}
return res;
}
int main(){
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
#endif
int n;
scanf("%d",&n);
getchar();
scanf("%s",s);
printf("%d",n-lis(s,n));
return 0;
}
很显然在这样的数据量下会TLE,所以采用O(nlogn)做法。
比方说一个字符串JAVASCRIPT,它的LIS为6。长度为3的序列中就有JST,AAC,CPT,IPT等等符合题意,那么哪个最“好”呢?很显然字符串越“小”,就越容易在后面插入新元素。
换句话说,要让某一长度的合法序列的“大小”尽可能“小”。
具体做法:1.dp[k]的含义变为长度为k的LIS的末尾元素的最小值。既然每个长度都是最小那么这个数组一定是递增的。
2.遍历原数组,如果当前元素不比dp末尾小就直接追加到dp末尾。 否则,找到dp数组中第一个大于当前元素的位置,把它替换为当前元素。这一过程可以用二分查找,故整体时间复杂度为O(nlogn)。
#include <cstdio>
#include <algorithm>
#include <cstring>
const int M=1000001;
using namespace std;
char s[M];
int lis(char *s,int n) {
if(n==0) return 0;
if(n==1) return 1;
static char dp[M];
int res=1;
fill(dp,dp+n+1,0);
/*O(N^2)
for(int i=1;i<n;i++) {
for(int j=0;j<i;j++) {
if(s[i]>=s[j]) {
dp[i]=max(dp[i],dp[j]+1);
res=max(res,dp[i]);
}
}
}*/
dp[res]=s[0];
for(int i=1;i<n;i++) {
if(s[i]>=dp[res]) {
//如果有一个不小于当前元素
dp[++res]=s[i];
}
else{
int j=upper_bound(dp+1,dp+res,s[i])-dp; //找第一个大于dp的元素
dp[j]=s[i];
}
}
puts(dp+1);
return res;
}
int main(){
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
#endif
int n;
scanf("%d",&n);
getchar();
scanf("%s",s);
printf("%d",n-lis(s,n));
return 0;
}
很明显的尺取法,可能是给的数据没那么强,所以才侥幸通过→_→
#include <cstdio>
#include <algorithm>
#include <vector>
const int M=10000001;
using namespace std;
int a[M];
int main(){
int n,x;
while(~scanf("%d%d",&n,&x)) {
//a.push_back(0);
int sum=0,l=1,r=1,l_res=l,r_res=r;
for(int i=1;i<=n;i++) {
//int m;
scanf("%d",&a[i]);
//a.push_back(m);
if(sum<x) {
sum+=a[i];
r=i;
}
}
int minlen=n,tmp=r-l+1;
while(r<=n) {
while(l<r&&sum>=x) {
sum-=a[l];
l++;
}
if(r-l+1<minlen) {
l_res=l-1;
r_res=r;
minlen=r-l+1;
}
while(sum<x&&r<=n) { //要防止越界
r++;
sum+=a[r];
}
}
printf("%d %d\n",l_res,r_res);
}
return 0;
}