zoukankan      html  css  js  c++  java
  • 划分sol

    划分

    • 很好的dp优化题
    • 考虑最简单的dp,设f[i][j]表示上一位置为j,当前位置为i,j+1~i为划分的一段,得到的最小值
    • 这样可以的到36分,(O(n^3))
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define SZ(x) ((int)x.size())
    #define ALL(x) x.begin(),x.end()
    #define U(i,u) for(register int i=head[u];i;i=nxt[i])
    #define rep(i,a,b) for(register int i=(a);i<=(b);++i)
    #define per(i,a,b) for(register int i=(a);i>=(b);--i)
    using namespace std;
    typedef long double ld;
    typedef long long ll;
    typedef unsigned int ui;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    template<class T> inline void read(T &x){
    	x=0;char c=getchar();int f=1;
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=f;
    }
    template<class T> inline void cmin(T &x, T y){x=x>y?y:x;}
    const int N=5001;
    const ll INF=100000000000000010;
    int n,m;
    ll a[N],f[N][N],sum[N],ans=INF;
    int main(){
    	read(n);read(m);rep(i,1,n)read(a[i]),sum[i]=sum[i-1]+a[i];sum[0]=0;
    	rep(i,0,n)rep(j,0,n)f[i][j]=INF;f[0][0]=0;
    	rep(i,1,n){
    		rep(j,0,i-1){
    			rep(k,0,j){
    				if(k==j&&j!=0)continue;
    				if(sum[i]-sum[j]>=sum[j]-sum[k])
    					cmin(f[i][j],f[j][k]+(sum[i]-sum[j])*(sum[i]-sum[j]));
    				if(i==n)cmin(ans,f[i][j]);
    			}
    		}
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
    • 考虑如果中间一维j是固定的,在i递减的时候,k是递增的,那么维护f[j][k]的最小值进行转移,同时将j这一维提到外面,i这一维倒序做,k递增
    • 这样就可以去掉k这一维,做到(O(n^2))
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define SZ(x) ((int)x.size())
    #define ALL(x) x.begin(),x.end()
    #define U(i,u) for(register int i=head[u];i;i=nxt[i])
    #define rep(i,a,b) for(register int i=(a);i<=(b);++i)
    #define per(i,a,b) for(register int i=(a);i>=(b);--i)
    using namespace std;
    typedef long double ld;
    typedef long long ll;
    typedef unsigned int ui;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    template<class T> inline void read(T &x){
    	x=0;char c=getchar();int f=1;
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=f;
    }
    template<class T> inline void cmin(T &x, T y){x=x>y?y:x;}
    const int N=5001;
    const ll INF=100000000000000010;
    int n,m;
    ll a[N],f[N][N],sum[N],ans=INF;
    int main(){
    	read(n);read(m);rep(i,1,n)read(a[i]),sum[i]=sum[i-1]+a[i];sum[0]=0;
    	rep(i,0,n)rep(j,0,n)f[i][j]=INF;f[0][0]=0;
    	rep(i,1,n)f[i][0]=sum[i]*sum[i];
    	rep(j,1,n-1){
    		int pos=0,k=0;
    		ll mx=INF;
    		per(i,n,j+1){
    			while(sum[j]-sum[k]>sum[i]-sum[j]&&k<j-1)++k;
    			if(sum[j]-sum[k]>sum[i]-sum[j])break;
    			pos=max(k,pos);while(pos<j){
    				if(f[j][pos]<=f[j][k])k=pos;
    				++pos;
    			}
    			if(sum[j]-sum[k]<=sum[i]-sum[j])cmin(f[i][j],f[j][k]+(sum[i]-sum[j])*(sum[i]-sum[j]));
    		}	
    	}
    	rep(i,0,n)cmin(ans,f[n][i]);
    	printf("%lld",ans);
    	return 0;
    }
    
    • 通过打表,其实挺明显,f[i][1...n]是递减的,所以贪心考虑要求最后被划分的一段尽量小
    • 用一个单调队列维护d(i)表示i这一位置贪心转移后最后一段大小,并且在决策的时候要尽量取i大的
    • 同时dp数组也可以省一维了,直接贪心转移,复杂度(O(n)),可以得到88分
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define SZ(x) ((int)x.size())
    #define ALL(x) x.begin(),x.end()
    #define U(i,u) for(register int i=head[u];i;i=nxt[i])
    #define rep(i,a,b) for(register int i=(a);i<=(b);++i)
    #define per(i,a,b) for(register int i=(a);i>=(b);--i)
    using namespace std;
    typedef long double ld;
    typedef long long ll;
    typedef unsigned int ui;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    template<class T> inline void read(T &x){
    	x=0;char c=getchar();int f=1;
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=f;
    }
    template<class T> inline void cmin(T &x, T y){x=x>y?y:x;}
    const int N=4e7+10;
    int n,m,l,r;
    ll a[N],f[N],su[N],d[N],q[N];
    int main(){
    	read(n);read(m);rep(i,1,n)read(a[i]),su[i]=su[i-1]+a[i];
    	l=1,r=1;q[1]=0;//单调队列要考虑保留0这个决策
    	rep(i,1,n){
    		while(l<r&&d[q[l+1]]+su[q[l+1]]<=su[i])++l;//只要更右边有合理决策,就会往右边走,使得d[i]尽量小
    		d[i]=su[i]-su[q[l]];f[i]=f[q[l]]+d[i]*d[i];
    		while(l<r&&d[q[r]]+su[q[r]]>=d[i]+su[i])--r;
    		q[++r]=i;
    	}
    	printf("%lld",f[n]);
    	return 0;
    }
    
    • 最后3个点可以考虑高精度或者__int128
    • 用__int128的话同时要优化空间,记录每个点是从哪个点转移过来,在最后计算即可,得到100分
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define SZ(x) ((int)x.size())
    #define ALL(x) x.begin(),x.end()
    #define U(i,u) for(register int i=head[u];i;i=nxt[i])
    #define rep(i,a,b) for(register int i=(a);i<=(b);++i)
    #define per(i,a,b) for(register int i=(a);i>=(b);--i)
    using namespace std;
    typedef long double ld;
    typedef __int128 ll;
    typedef unsigned int ui;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    template<class T> inline void read(T &x){
    	x=0;char c=getchar();ll f=1;
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=f;
    }
    template <typename T> inline void print(T x) {if(x<0)putchar('-'),x =-x;if(x < 10)putchar(x + 48);else print(x/10),putchar(x%10+48);}
    template<class T> inline void cmin(T &x, T y){x=x>y?y:x;}
    const int N=4e7+10;
    const int M=1e5+10;	
    const int P=(1<<30);
    int n,opt,l,r,pre[N],q[N];
    long long su[N];
    int p2[M],l2[M],r2[M],b[N];
    long long d(int x){return su[x]-su[pre[x]];}
    int main(){
    	read(n);read(opt);
    	if(opt){
    		int x,y,z,m;read(x);read(y);read(z);read(b[1]);read(b[2]);read(m);rep(i,1,m)read(p2[i]),read(l2[i]),read(r2[i]);
    		rep(i,3,n)b[i]=(0ll+1ll*x*b[i-1]+1ll*y*b[i-2]+z)%P;rep(i,1,m)rep(j,p2[i-1]+1,p2[i])su[j]=b[j]%(r2[i]-l2[i]+1)+l2[i]+su[j-1];
    		l=1,r=1;q[1]=0;//单调队列要考虑保留0这个决策
    		rep(i,1,n){
    			while(l<r&&d(q[l+1])+su[q[l+1]]<=su[i])++l;//只要更右边有合法决策,就会往右边走,使得d[i]尽量小
    			pre[i]=q[l];
    			while(l<r&&d(q[r])+su[q[r]]>=d(i)+su[i])--r;//单调队列维护了d[i]+su[i]
    			q[++r]=i;
    		}
    		ll ans=0,tmp;
    		int p=n;while(p){tmp=d(p);tmp*=d(p);ans+=tmp;p=pre[p];}print(ans);
    	}else{
    		int x;rep(i,1,n)read(x),su[i]=su[i-1]+x;l=1,r=1;q[1]=0;//单调队列要考虑保留0这个决策
    		rep(i,1,n){
    			while(l<r&&d(q[l+1])+su[q[l+1]]<=su[i])++l;//只要更右边有合法决策,就会往右边走,使得d[i]尽量小
    			pre[i]=q[l];
    			while(l<r&&d(q[r])+su[q[r]]>=d(i)+su[i])--r;//单调队列维护了d[i]+su[i]
    			q[++r]=i;
    		}
    		ll ans=0,tmp;
    		int p=n;while(p){tmp=d(p);tmp*=d(p);ans+=tmp;p=pre[p];}print(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    BLE 5协议栈-安全管理层
    BLE 5协议栈-通用属性规范层(GATT)
    BLE 5协议栈-属性协议层(ATT)
    BLE 5协议栈-逻辑链路控制与适配协议层(L2CAP)
    BLE 5协议栈-主机控制接口(HCI)
    BLE 5协议栈-直接测试模式
    BLE 5协议栈-链路层
    BLE 5协议栈-物理层
    名词缩写
    C#中数据库事务、存储过程基本用法
  • 原文地址:https://www.cnblogs.com/hangzz/p/13405711.html
Copyright © 2011-2022 走看看