一:尺取法
/**
尺取法,给定长度为n的数列a(0~n-1),以及整数S,求出总和不小于S的连续子序列
的长度的最小值
输入:
10 15
5 1 3 5 10 7 4 9 2 8
输出:
2
**/
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,S;
int a[100];
int sum[100];
void solve(){
//计算sum
for(int i=0;i<n;i++){
sum[i+1]=sum[i]+a[i];
}
if(sum[n]<S){
//解不存在
printf("0\n");
return ;
}
int res=n;
for(int s=0;sum[s]+S<=sum[n];s++){
int t=lower_bound(sum+s,sum+n,sum[s]+S)-sum;
res=min(res,t-s);
}
printf("%d\n",res);
}
int main(){
scanf("%d%d",&n,&S);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
solve();
return 0;
}
二:翻转(开关问题)
/**
有N头牛,每头牛要么面朝前方(F)或者面朝后方(B)。现在可以连续驱使连续的K头牛反转。求使得所有的牛面朝前方的最小操作数
和对应的K是多少?
输入:
7
BBFBFBB
输出:
3 3
**/
#include<stdio.h>
#include<string.h>
int N;
int dir[100]; //牛的方向(0:F,1:B)
int f[100]; //区间[i,i+k-1] //是否进行反转
//固定K,求对应的最小操作回数
//无解的话则返回-1
int calc(int K){
memset(f,0,sizeof(f));
int res=0;
int sum=0; //能影响到当前点的f和
for(int i=0;i+K<=N;i++){
//计算区间[i,i+K-1]
if((dir[i]+sum)%2!=0){
//当sum为偶数时以前的反转对当前无影响,dir为1时,然后结合dir[i]最初状态
//当sum为奇数时以前的反转使状态与原始相反,然后结合dir[i]最初状态
res++; //翻转次数加1
f[i]=1; //记录区间[i,i-K+1]翻转
}
sum+=f[i]; //加上f[i],以便判断当前翻转是否对下一个翻转造成影响
if(i-K+1>=0){
sum-=f[i-K+1];//减去将对下一个区间没有影响的f[i]
}
}
//检查剩下的牛是否有面朝后面的情况
for(int i=N-K+1;i<N;i++){
if((dir[i]+sum)%2!=0){
//无法翻转但是需要翻转,无解
return -1;
}
if(i-K+1>=0){
sum-=f[i-K+1];
}
}
return res;
}
void solve(){
int K=1,M=N;
for(int k=1;k<=N;k++){
int m=calc(k);
if(m>=0&&M>m){
M=m;
K=k;
}
}
printf("%d %d\n",K,M);
}
int main(){
char str[100];
scanf("%d",&N);
scanf("%s",str);
for(int i=0;i<N;i++){
if(str[i]=='F'){
dir[i]=0;
}else{
dir[i]=1;
}
}
solve();
return 0;
}