三个点三道题。
先说一下考试过程。拿到题,先看了第一题,一道广搜,直接花了10分钟左右打完,调完,两个样例都过了。
然后去看T3,看样子是个分块,但没学过不会写。。又像一个线段树,但是不知道怎么维护。于是先暴力打了个部分分,T3先放在一边。
现在过了半个点吧大概,然后去看T2。嗯。。看样子是道动态规划,又像一道模拟。题目给的条件也很简单,在纸上推了一会式子,把最优解给想出来。看了数据范围,动态规划应该就行了吧。打完了试了样例,也过了。
最后回去看T3,本来想交暴力的,卡卡常,颓了一会。又发现线段树好像也能写,每次维护最大值和最小值就行了。(啊啊啊mid一定是l+r>>1,手残把l写成1调了好长时间)。样例过了,但不知道能不能过吧。。
T1
一道很水的广搜题,也可以算是很经典的题了吧。
#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
return x*f;
}
inline void print(int x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
const int M = 2e5+10;
int n,k;
int vis[M],ans[M];
queue<int>q;
void bfs(){
vis[n] = 1;
ans[n] = 0;
q.push(n);
while(!q.empty()){
int x = q.front();
q.pop();
if(x == k) return;
if(x+1<=100000 && !vis[x+1]){
q.push(x+1);
vis[x+1] = 1;
ans[x+1] = ans[x]+1;
}
if(x-1>=0 && !vis[x-1]){
q.push(x-1);
vis[x-1] = 1;
ans[x-1] = ans[x]+1;
}
if(x*2<=100000 && !vis[x*2]){
q.push(x*2);
vis[x*2] = 1;
ans[x*2] = ans[x]+1;
}
}
}
signed main(){
freopen("catchcow.in","r",stdin);
freopen("catchcow.out","w",stdout);
n=read(),k=read();
if(k<n){
printf("%d",n-k);
return 0;
}
bfs();
printf("%d",ans[k]);
return 0;
}
T2
一道动态规划吧,方程也很好推。但要注意,数据范围可以两次DP,一次是不下降,一次是不上升,两次去一个最小值。
#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
return x*f;
}
inline void print(int x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
const int M = 2010;
const int inf = 1e9;
int f[M][M],a[M],b[M];
int ans;
int n;
void init(){
memset(f,0,sizeof(f));
for(re int i(1) ; i<=n ; ++i) f[i][0] = inf;
}
bool cmp(int x,int y) {return x > y;}
signed main(){
freopen("grading.in","r",stdin);
freopen("grading.out","w",stdout);
n=read();
for(re int i(1) ; i<=n ; ++i) a[i] = read(),b[i] = a[i];
sort(b+1,b+n+1);
init();
for(re int i(1) ; i<=n ; ++i){
for(re int j(1) ; j<=n ; ++j){
f[i][j] = min(f[i][j-1],f[i-1][j]+abs(a[i]-b[j]));
}
}
ans = f[n][n];
init();
sort(b+1,b+n+1,cmp);
for(re int i(1) ; i<=n ; ++i){
for(re int j(1) ; j<=n ; ++j){
f[i][j] = min(f[i][j-1],f[i-1][j]+abs(a[i]-b[j]));
}
}
printf("%d",min(ans,f[n][n]));
return 0;
}
T3
暴力很好写吧,怎么说怎么写就行。线段是维护区间的最大值和最小值。考虑一个区间,如果最大值小于c,那么返回0,如果最小值大于c,返回这个区间的长度。其它的就是维护tag标记,每次下传就行,普通的线段树操作。
#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
return x*f;
}
inline void print(int x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
const int M = 4e6+1;
int a[M];
int n,q;
struct tree{
int mi,mx,tag;
}t[M];
inline void update(int k){
t[k].mx = max(t[k<<1].mx,t[k<<1|1].mx);
t[k].mi = min(t[k<<1].mi,t[k<<1|1].mi);
}
inline void pushdown(int k){
if(t[k].tag){
t[k<<1].tag += t[k].tag;
t[k<<1|1].tag += t[k].tag;
t[k<<1].mx += t[k].tag;
t[k<<1|1].mx += t[k].tag;
t[k<<1].mi += t[k].tag;
t[k<<1|1].mi += t[k].tag;
t[k].tag = 0;
}
}
inline void build(int k,int l,int r){
if(l==r){t[k].mi=t[k].mx=a[l];return;}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
update(k);
}
inline void add(int k,int l,int r,int x,int y,int c){
if(x<=l&&r<=y){
t[k].mx+=c;
t[k].mi+=c;
t[k].tag+=c;
return;
}
pushdown(k);
int mid = (l+r)>>1;
if(x<=mid) add(k<<1,l,mid,x,y,c);
if(y>mid) add(k<<1|1,mid+1,r,x,y,c);
update(k);
}
inline int query(int k,int l,int r,int x,int y,int c){
if(x<=l&&r<=y&&c<=t[k].mi) return r-l+1;
if(x<=l&&r<=y&&c>t[k].mx) return 0;
pushdown(k);
int mid = (l+r)>>1,ans=0;
if(x<=mid) ans+=query(k<<1,l,mid,x,y,c);
if(y>mid) ans+=query(k<<1|1,mid+1,r,x,y,c);
update(k);
return ans;
}
signed main(){
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
n=read(),q=read();
for(re int i(1) ; i<=n ; ++i) a[i] = read();
build(1,1,n);
for(re int i(1) ; i<=q ; ++i){
char ch;
int l,r,x;
cin >> ch;
l=read(),r=read(),x=read();
if(ch == 'M') add(1,1,n,l,r,x);
else printf("%d\n",query(1,1,n,l,r,x));
}
return 0;
}