• 模拟赛42 题解


    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;
    }
    
    
  • 相关阅读:
    python学习笔记-面向对象进阶复习小结
    python学习笔记-类的静态属性,类方法和静态方法
    python学习笔记-面向对象的继承、多态、封装
    python学习笔记-python简介
    python学习笔记-列表、元组字典
    python学习笔记-常用数据类型之字符串
    python学习笔记-函数,递归和内置函数
    python学习笔记-文件操作
    python学习笔记-迭代器与生成器
    python学习笔记-装饰器
  • 原文地址:https://www.cnblogs.com/wwcdcpyscc/p/14052874.html
Copyright © 2020-2023  润新知