zoukankan      html  css  js  c++  java
  • SGU 183 Painting the balls

    题目描述

    小宝把(N)个白球排成一列,他想把一些白球刷为黑色,且任意连续(m)个球中至少要有(2)个黑球。

    小宝知道他需要(C_i)的染料刷第(i)个球。请你帮小宝算算他最少需要多少染料。

    Input

    第一行两个整数(n)(m)

    第二行(n)个整数,表示(C_i)

    对于(30\%)的数据(n)的数据范围([1,20])

    对于(60\%)的数据(n)的数据范围([1,500]),(m)的范围([2,100]);

    对于(80\%)的数据(n)的数据范围([1,10000]),(m)的范围([2,1000]);

    对于(100\%)的数据(n)的数据范围([1,20000]),(m)的范围([2,2000]),(m≤n),(C_i)的范围([1,20000]);

    Output

    输出最少需要的染料数量。

    Sample Input

    6 3
    1 5 6 2 1 3
    

    Sample Output

    9
    

    可以发现对于一个状态到下一个状态进行转移时,只用关心最后两个被染色的位置,(注意不是一个)

    这样我们可以非常方便的打出时间复杂度为(O(n*n*m))的代码。

    (dp[i][j])表示前(j)个球满足条件,最后的球在(j)(i)上的最小代价。

    那么(dp[i][k])就可以由(dp[j][i])转移过来,其中由于连续(m)个球必须要有(2)个黑球所以(j)必须要在([k-m,i-1])的区间内才行。

    (dp[i][j]=min(dp[k][i]+A[j]),j-m le k le i-1;)

    由此可以过掉(60\%)的数据。

    代码如下

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define u64 unsigned long long
    #define u32 unsigned int
    #define reg register
    #define Raed Read
    #define debug(x) cerr<<#x<<" = "<<x<<endl;
    #define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
    #define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
    #define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
    #define erep(i,G,x) for(reg int i=(G).Head[x]; i; i=(G).Nxt[i])
    
    inline int Read() {
    	int res  = 0, f = 1;
    	char c;
    	while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
    	do res = (res << 3) + (res << 1) + (c ^ 48);
    	while (c = getchar(), c >= 48 && c <= 57);
    	return f ? res : -res;
    }
    
    template<class T>inline bool Min(T &a, T const&b) {
    	return a > b ? a = b, 1 : 0;
    }
    template<class T>inline bool Max(T &a, T const&b) {
    	return a < b ? a = b, 1 : 0;
    }
    
    const int N=2e4+5,M=1e5+5,mod=205;
    
    bool MOP1;
    
    int n,m,A[N];
    
    struct T260 {
    	int dp[505][505];
    	inline void solve(void) {
    		memset(dp,63,sizeof dp);
    		rep(i,1,m)rep(j,i+1,m)dp[i][j]=A[i]+A[j];
    		rep(i,m+1,n) {
    			int L=i-m,R=i-1;
    			rep(j,L,R)rep(k,j+1,R)Min(dp[k][i],dp[j][k]+A[i]);
    		}
    		int L=n-m+1,R=n,Ans=1e9;
    		rep(i,L,R)rep(j,i+1,R)Min(Ans,dp[i][j]);
    		printf("%d",Ans);
    	}
    } P60;
    
    bool MOP2;
    
    inline void _main(void) {
    	n=Raed(),m=Read();
    	rep(i,1,n)A[i]=Read();
    	P60.solve();
    }
    
    signed main() {
    #define offline1
    #ifdef offline
    	freopen("paint.in", "r", stdin);
    	freopen("paint.out", "w", stdout);
    	_main();
    	fclose(stdin);
    	fclose(stdout);
    #else
    	_main();
    #endif
    	return 0;
    }
    

    对于相同的(i),如果对(j)由大到小枚举,会有重叠的部分,可以直接以(O(1))的复杂度得到(dp[k][i]),从而把复杂度降到了(O(M*N))

    可是我们又发现,但我们沿用上面的(dp)定义时,空间已经不够我们开了。

    而倒数第二个球又一定在倒数第一个球前(m)个以内。

    因此,我们只用把(dp)状态改为(dp[i][j])表示最后一个为(i),倒数第二个位距离(i)(j)的最小代价。

    可是,最麻烦的事情来了,空间还是不够!!!

    因此,我们可以用滚动数组进行优化,由于对于当前的(dp[i][j]),有用的只有([i-m+1,i-1])范围内的(dp)值。

    因此,我们可以把第一维压成(m),对(i)进行取模节省空间。

    代码如下

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define u64 unsigned long long
    #define u32 unsigned int
    #define reg register
    #define Raed Read
    #define debug(x) cerr<<#x<<" = "<<x<<endl;
    #define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
    #define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
    #define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
    #define erep(i,G,x) for(reg int i=(G).Head[x]; i; i=(G).Nxt[i])
    
    inline int Read() {
    	int res  = 0, f = 1;
    	char c;
    	while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
    	do res = (res << 3) + (res << 1) + (c ^ 48);
    	while (c = getchar(), c >= 48 && c <= 57);
    	return f ? res : -res;
    }
    
    template<class T>inline bool Min(T &a, T const&b) {
    	return a > b ? a = b, 1 : 0;
    }
    template<class T>inline bool Max(T &a, T const&b) {
    	return a < b ? a = b, 1 : 0;
    }
    
    const int N=2e4+5,M=1e5+5,mod=205;
    
    bool MOP1;
    
    int n,m,A[N];
    
    struct T2100 {
    	int dp[2005][2005],Mod[N];
    	inline void solve(void) {
    		int Ans=1e9;
    		rep(i,1,n)Mod[i]=i%m;
    		rep(i,1,n) {
    			memset(dp[Mod[i]],63,sizeof dp[Mod[i]]);
    			rep(j,max(0,i-m+1),i-1)Min(dp[Mod[i]][j+m-i],dp[Mod[j]][i-j]+A[i]);
    			drep(j,m,0)Min(dp[Mod[i]][j],dp[Mod[i]][j+1]);
    			if(i>=n-m+1)Min(Ans,dp[Mod[i]][n-i]);
    		}
    		printf("%d",Ans);
    	}
    } P100;
    
    bool MOP2;
    
    inline void _main(void) {
    	n=Raed(),m=Read();
    	rep(i,1,n)A[i]=Read();
    	P100.solve();
    }
    
    signed main() {
    #define offline1
    #ifdef offline
    	freopen("paint.in", "r", stdin);
    	freopen("paint.out", "w", stdout);
    	_main();
    	fclose(stdin);
    	fclose(stdout);
    #else
    	_main();
    #endif
    	return 0;
    }
    
  • 相关阅读:
    第八周上机作业
    第七次作业
    第七周上机
    第六周作业
    4.9上机作业
    第五周作业
    第四周作业
    第二次上机作业
    第三周作业
    第九周上机练习
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11298285.html
Copyright © 2011-2022 走看看