zoukankan      html  css  js  c++  java
  • Codeforces1461F.Mathematical Expression dp,贪心

    Codeforces1461F.Mathematical Expression

    题意

    给定一个长度为(n)的整数数组(a)和一个长度不大于(3)的由运算符组成的字符串(s),让你在(a)中所有相邻的数字之间添加一个(s)中的运算符,使这个算术表达式的值最大。

    (nle 10^5,0le a_i le 9)(s)由"-","+","*"组成。

    分析

    (s)中只包括一种运算符时,只能填充这个运算符,"+-*"可以等价于"+*",“+-”等价于"+",那么就只剩下两种情况。

    • “-*",两个大于(0)的数之间一定是填充"*",设(x>0)(0x)之间若填充”-“会出现负数,所以要用"*",(x0)之间用"-"。
    • "+*",对于这种情况,我们以(0)作为分割点,(0)的两边一定是"+",对于分割出的每一段分别考虑,假设某一段在原数组中为区间([l,r]),对于这个区间开头的一段(1)和结尾的一段(1)每个数字之间都填充"+",对于中间的一段我们自然可以想到若它们的乘积非常大(大于(10^{16})),一定是全部乘起来,否则对于(2,3,1,1,cdots,1,1,2,3)这种中间有很长的一段(1)的数据,(2 imes 3+1+1+cdots+1+1+2 imes 3)这样会更大,考虑动态规划,设(dp[i])表示前(i)个数后已经添加运算符的最大值,从(i)转移到(j(j>i)),有两种情况,([i+1,j-1])这一段每个数字后面都填充加号或者都填充乘号,这一段后添加加号,这样是(n^2)的,因为连续的一段(1)一定是全部加起来或者和两边乘起来,设(nex[i])表示(i)所在连续(1)的段的段尾,(j)就可以不断的跳(max(j+1,nex[i]))来加速转移,因为这个区间所有数字乘起来都不大于(10^{16}),所以(j)最多跳(log(10^{16}))次,记录转移的前驱,回溯更新答案即可。

    Code

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<sstream>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<bitset>
    #include<queue>
    #include<cmath>
    #include<stack>
    #include<set>
    #include<map>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=1e5+10;
    const ll inf=1e16;
    int n,a[N];
    vector<int>w;
    string s;
    ll pre[N],sum[N],dp[N];
    int f[N],nex[N];
    char c[N];
    char ans[N];
    void gao(int l,int r){
    	int dl=l,dr=r;
    	while(a[dl]==1&&dl<=r){
    		ans[dl]='+';
    		++dl;
    	}
    	while(a[dr]==1&&l<=dr){
    		ans[dr]='+';
    		--dr;
    	}
    	l=dl,r=dr;
    	if(l>r) return;
    	pre[l-1]=1;
    	sum[l-1]=0;
    	int flag=0;
    	rep(i,l,r){
    		pre[i]=pre[i-1]*a[i];
    		sum[i]=sum[i-1]+a[i];
    		if(pre[i]>inf){
    			flag=1;
    			break;
    		}
    	}
    	if(flag){
    		rep(i,l,r-1) ans[i]='*';
    		ans[r]='+';
    		return;
    	}
    	int now=l;
    	rep(i,l,r){
    		now=max(now,i);
    		while(a[now]==1&&now<=n) ++now;
    		if(now==i) nex[i]=now;
    		else nex[i]=now-1;
    	}
    	rep(i,l-1,r) dp[i]=0;
    	rep(i,l-1,r-1){
    		for(int j=i+1;j<=r;j=max(j+1,nex[j])){
    			if(pre[j]/pre[i]+dp[i]>dp[j]){
    				dp[j]=pre[j]/pre[i]+dp[i];
    				f[j]=i;
    				c[j]='*';
    			}
    			if(sum[j]-sum[i]+dp[i]>dp[j]){
    				dp[j]=sum[j]-sum[i]+dp[i];
    				f[j]=i;
    				c[j]='+';
    			}
    		}
    	}
    	now=r;
    	while(now!=l-1){
    		int x=f[now];
    		rep(i,x+1,now-1) ans[i]=c[now];
    		ans[now]='+';
    		now=x;
    	}
    }
    int main(){
    	//ios::sync_with_stdio(false);
    	//freopen("in","r",stdin);
    	cin>>n;
    	rep(i,1,n) cin>>a[i];
    	cin>>s;
    	if(sz(s)==1){
    		rep(i,1,n-1){
    			cout<<a[i]<<s[0];
    		}
    		cout<<a[n]<<endl;
    	}else if(s=="+-"||s=="-+"){
    		rep(i,1,n-1){
    			cout<<a[i]<<"+";
    		}
    		cout<<a[n]<<endl;
    	}else if(s=="+*"||s=="*+"||sz(s)==3){
    		int l=1;
    		for(int i=1;i<=n;i++){
    			if(a[i]==0){
    				if(l<=i-1) gao(l,i-1);
    				ans[i]='+';
    				l=i+1;
    			}
    		}
    		if(l<=n) gao(l,n);
    		rep(i,1,n-1) cout<<a[i]<<ans[i];
    		cout<<a[n]<<endl;
    	}else if(s=="-*"||s=="*-"){
    		cout<<a[1];
    		rep(i,2,n){
    			if(a[i-1]>0&&a[i]==0) cout<<'-';
    			else cout<<"*";
    			cout<<a[i];
    		}
    		cout<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    python-局部变量与全局变量作用域
    python-函数(上):函数返回值、函数调用、前向引用
    python-文件读写
    python-输入和输出
    python-模块介绍及os模块的方法
    python-continue和break的区别
    python-for循环
    python-while循环
    python-三元运算和if...else
    python-数据类型(下) :byte、列表、元组、集合
  • 原文地址:https://www.cnblogs.com/xyq0220/p/14154551.html
Copyright © 2011-2022 走看看