T1
前言:
很奇怪为什么考场上没想出来。
第一眼看成区间dp了(可能是因为昨天晚测的影响),于是整出了(n^5)的奇怪转移。
然后又想爆搜剪枝。本来以为数据稍微水一点的话,剪枝应该可以过。写出来之后发现大样例都过不了。。。
于是弃掉重新回去想dp。状态都设出来了,但是因为耗时太长导致对题目难度估计错误,再加上心态有点乱,没有仔细去推转移,就以为复杂度不对。于是就gg了。
PS:考场上先写了随机化后写了dfs。后来发现随机化WA了。瞎jb剪枝得到了-30分的好成绩。
解析:
可以发现,只能按照时间顺序选点,现在不选,以后就不能再选了。
而且发现,这个人要移动,当且仅当他从一个新闻地点到另一个新闻地点。
所以,令dp[i][j]表示选前i个点,选了j个的最小收益。
那么,dp[i][j]可以转移到dp[i+k][j+1];
枚举(n^2),转移线性。
于是就没了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=100+10;
typedef long long ll;
int read(){
int w=0,x=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') x=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<1)+(w<<3)+(ch^48);
ch=getchar();
}
return x*w;
}
struct node{
int x,y;
}b[maxn];
int n,ans,Time;
ll D;
int p[maxn];
ll dp[maxn][maxn];
void Solve(){
srand(time(NULL));
n=read();
for(int i=1;i<=n;++i){
b[i].x=read();
b[i].y=read();
}
scanf("%lld",&D);
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
int ans=0;
for(int i=0;i<n;++i){
for(int j=0;j<=i;++j){
for(int k=1;k<=n-i;++k){
dp[i+k][j+1]=min(dp[i+k][j+1],dp[i][j]+abs(b[i].x-b[i+k].x)+abs(b[i].y-b[i+k].y));
if(dp[i+k][j+1]<=D-abs(b[i+k].x)-abs(b[i+k].y)) ans=max(ans,j+1);
}
}
}
printf("%d
",ans);
}
int main(){
freopen("news.in","r",stdin);
freopen("news.out","w",stdout);
Solve();
return 0;
}
T4
前言:
这题考场上想到了和正解相似的思路,但还是差点劲。。。
解析:
我们可以用w[i]表示以i为起点的答案。
那么发现,一个点只会对它前面小于它的数有贡献。
因此,用f[i]维护i前面地一个大于等于i的数的下标。每次修改,区间右移就去掉不合法的贡献即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1000000+10;
typedef long long ll;
ll read(){
ll w=0,x=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') x=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<1)+(w<<3)+(ch^48);
ch=getchar();
}
return x*w;
}
int n,k,top;
int f[maxn],Stack[maxn],tree[maxn<<2],lazy[maxn<<2];
ll a[maxn];
void update(int rt,int w){
tree[rt]+=w;
lazy[rt]+=w;
}
void pushdown(int rt){
if(lazy[rt]==0) return ;
update(rt<<1,lazy[rt]);
update(rt<<1|1,lazy[rt]);
lazy[rt]=0;
}
void modify(int rt,int l,int r,int s,int t,int x){
if(s<=l&&r<=t){
update(rt,x);
return;
}
int mid=(l+r)>>1;
pushdown(rt);
if(s<=mid) modify(rt<<1,l,mid,s,t,x);
if(t>mid) modify(rt<<1|1,mid+1,r,s,t,x);
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void Solve(){
n=read();
k=read();
for(int i=1;i<=n;++i) a[i]=read();
Stack[++top]=1;
for(int i=2;i<=n;++i){
while(top&&a[Stack[top]]<a[i]) top--;
f[i]=Stack[top];
Stack[++top]=i;
}
//for(int i=1;i<=n;++i) printf("f[%d]=%d
",i,f[i]);
for(int i=1;i<=k;++i) if(f[i]<i) modify(1,1,n,f[i]+1,i,1);
printf("%d ",tree[1]);
int x=1;
for(int i=k+1;i<=n;++i){
if(f[x]<x) modify(1,1,n,f[x]+1,x,-1);
if(f[i]<i) modify(1,1,n,f[i]+1,i,1);
printf("%d ",tree[1]);
x++;
}
}
int main(){
freopen("lizard.in","r",stdin);
freopen("lizard.out","w",stdout);
Solve();
return 0;
}