B-Best Cow Fence
序列的平均值是满足单调性的,考虑对平均值二分答案。它的上下界分别可以设置为序列的最小和最大值。
由于直接维护区间的平均值是不容易的,我们考虑每次检验这个平均值的时候,让这个数组减去平均值,然后判断是否有一个区间和是大于0的,就知道这样的平均值是不是存在。
我们记录下这个数组以后就去处理一下它的前缀和,然后从区间的第k个数开始,然后维护区间和,枚举右端点的同时更新左端点的最小值,就可以求出右端点的区间的最大值,判断它是不是大于0就可以了
#include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
const int maxn=1e5+50;
double a[maxn],b[maxn],s[maxn],r=-1,l=0x3f3f3f3f;
int n,k;
bool check(double mid) {
double minn=1e10,ans=-1;
for(int i=1;i<=n;i++) s[i]=a[i]-mid+s[i-1];
for(int i=k;i<=n;i++){
minn=min(minn,s[i-k]);
ans=max(ans,s[i]-minn);
}
if(ans>0) return true;
else return false;
}
int main() {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i) {
scanf("%lf",&a[i]);
r=max(r,a[i]),l=min(l,a[i]);
}
while(l<=r-eps) {
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%d\n",int(1000*r));
return 0;
}
C-CF-1073C
这道题要求的答案是右端点减左端点+1的最大值,实际上这个就是区间长度,区间长度满足单调性,最小为0,最大为全部区间,二分这个答案。
然后我们分别去判定这个区间能否让这个机器人走到终点。读入以后我们就去记录它的前缀和,然后每次判定区间的时候,就先加上那些剩下的,然后问题就转化为判断给你多少步能不能走到终点。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+50;
int n,edx,edy;string s;
int rcnt[maxn],ucnt[maxn];
bool check(int len) {
int l=0,r=len-1;
for(;r<s.size();l++,r++) {
int dx=rcnt[n-1]-rcnt[r];
int dy=ucnt[n-1]-ucnt[r];
if(l!=0) dx+=rcnt[l-1],dy+=ucnt[l-1];
if((abs(edx-dx)+abs(edy-dy))<=len&&(len-abs(edx-dx)-abs(edy-dy))%2==0) return true;
}
return false;
}
int main() {
int ans=-1;
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>s>>edx>>edy;
for(int i=0;i<s.size();++i){
if(i>0) rcnt[i]+=rcnt[i-1],ucnt[i]+=ucnt[i-1];
if(s[i]=='R') rcnt[i]++;
else if(s[i]=='L') rcnt[i]--;
else if(s[i]=='U') ucnt[i]++;
else if(s[i]=='D') ucnt[i]--;
}
if(rcnt[n-1]==edx&&ucnt[n-1]==edy) {printf("0\n");return 0;}
int l=-1,r=n+1;
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}
POJ 1659
题意就是判断一个序列是否可图,我们每次都给这个序列排序,然后去判断这个点的度数能不能用后面的点消掉,这里有两种情况,一种是如果我现在这个点的度数比较大后面的不够我消,这个情况就不可图了。还有另外一种情况就是,如果我后面的点已经出现了负数,也就是实际上无法去消除前面点的度数,这个情况也不可图。然后我们只要去模拟这个过程就可以了。
这个题让我们学习到的点还有就是用模块化的写法来写程序会省事很多,有时候我们如果发现一种情况已经不可行,那我们就直接返回一个false,避免在循环里面多次打标记。
最后因为忘记打YES这道题还被卡了许久,因为一直在盯着图看,这件事就很让人伤心了
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=15;
struct node{ int d,pos; } de[maxn];
int n,vis[maxn][maxn];
bool cmp(node a,node b) {return a.d>b.d;}
inline void clear(){
memset(vis,0,sizeof(vis));
memset(de,0,sizeof(de));
}
bool check(){
for(int i=1;i<=n;i++) {
sort(de+i,de+n+1,cmp);
if(de[i].d>n-i) return false;
for(int j=i+1;j<=i+de[i].d;j++){
if(de[j].d==0) return false;
de[j].d--,vis[de[i].pos][de[j].pos]=1,vis[de[j].pos][de[i].pos]=1;
}
de[i].d=0;
}
return true;
}
int main(){
int line;
scanf("%d",&line);
while(line--){
clear();
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&de[i].d),de[i].pos=i;
if(check()) {
printf("YES\n");
for(int i=1;i<=n;i++) {
for(int j=1;j<n;j++) printf("%d ",vis[i][j]);
printf("%d\n",vis[i][n]);
}
printf("\n");
}
else printf("NO\n\n");
}
return 0;
}