• 【洛谷P1052】过河 离散化+dp


    题目大意:给定一个长度为 N 的序列,有 M 个点对答案的贡献为 1,其余为 0,现从起点出发,每次只能走 [s,t] 个单位,求从起点走到终点时答案贡献最小是多少。

    题解:由于 N 很大,无法直接记录状态。观察发现 M 很小,且 [s,t] 也很小,因此,考虑到只有在答案贡献为 1 的点的附近 dp 值才可能会发生变化,其余位置会导致大量的解的重复而浪费时间和空间。基于以上想法,考虑缩点,即:对于两个石子之间的距离来说,是否存在一个点 s0 使得当 s>s0 时,无论从前一个石子之前的任何位置,通过任何步数的组合,均可以到达 s ,则从 s0 到下一个石子的位置之前的 0 贡献部分可以被缩掉。这样,根据裴蜀定理可得,对于 (len>t(t-1)) 时,即可满足上述条件。

    代码如下

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e4+10;
    
    int n,s,t,m,l,pos[101];
    int dp[maxn];
    bool is[maxn];
    
    void read_and_parse(){
    	scanf("%d%d%d%d",&n,&s,&t,&m);
    	for(int i=1;i<=m;i++)scanf("%d",&pos[i]);
    }
    
    void solve(){
    	if(s==t){
    		int ans=0;
    		for(int i=1;i<=m;i++)if(pos[i]%s==0)++ans;
    		return (void)printf("%d
    ",ans);
    	}
    	sort(pos+1,pos+m+1);
    	for(int i=1;i<=m;i++)l+=min(pos[i]-pos[i-1],100),is[l]=1;
    	l+=min(n-pos[m],100);
    	memset(dp,0x3f,sizeof(dp));
    	dp[0]=0;
    	for(int i=1;i<=l+9;i++)
    		for(int j=s;j<=t;j++)if(i>=j)
    			dp[i]=min(dp[i],dp[i-j]+is[i]);
    	int ans=1e9;
    	for(int i=l;i<=l+9;i++)ans=min(ans,dp[i]);
    	printf("%d
    ",ans);
    }
    
    int main(){
    	read_and_parse();
    	solve();
    	return 0;	
    } 
    
  • 相关阅读:
    2月3日
    照片测试
    家属签证计时
    我来了
    090204 阴天
    重要提醒to 小爱
    小毛小毛
    C++Primer学习日程
    资料库字段存储文件记录的方式
    本日有点忙
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10596676.html
Copyright © 2020-2023  润新知