• The Preliminary Contest for ICPC China Nanchang National Invitational and International Silk-Road Programming Contest D


    移动火柴,使表达式的值最大化。

    题目存在限制条件,不能删除符号,每一个数字的位数不能发生变化,不能出现前导零,单个数字的值不会超过1e9。在这样的条件限制下,可以通过dp求解。

    定义dp[i][j],其中i为第i个数字,j为此刻已经使用的火柴总数,dp[i][j]即此时能取得的最大值。

    题目没有太多难点,整体就是类似背包的写法,但是存在很多细节,初始化需要特别注意,还有就是要排除前导零的干扰。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<stack>
    #include<map>
    #include<vector>
    #include<queue>
    #include<set>
    #include<iomanip>
    #include<cctype> 
    #include<ctime>
    using namespace std;
    typedef long long ll;
    #define edl putchar('
    ')
    #define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define ROF(i,a,b) for(int i=a;i>=b;i--)
    #define FORLL(i,a,b) for(ll i=a;i<=b;i++)
    #define ROFLL(i,a,b) for(ll i=a;i>=b;i--)
    #define mst(a) memset(a,0,sizeof(a))
    #define mstn(a,n) memset(a,n,sizeof(a))
    #define zero(x)(((x)>0?(x):-(x))<eps)
    #define si(a) scanf("%d",&a)
    #define sl(a) scanf("%lld",&a)
    #define sd(a) scanf("%lf",&a)
    #define ss(a) scanf("%s",a)
    inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
    int month[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    int dir[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{1,1},{1,-1},{-1,1}};
    const int MAXN=1e4+5;
    const int INF=1<<30;
    const ll mod=1e9+7;//998244353;
    const double eps=1e-8;
    const ll inff=0x3f3f3f3f3f3f3f3f;
    
    int cal(char c)
    {
    	if(c=='+'||c=='1') return 2;
    	if(c=='-') return 1;
    	if(c=='7') return 3;
    	if(c=='4') return 4;
    	if(c=='2'||c=='3'||c=='5') return 5;
    	if(c=='6'||c=='9'||c=='0') return 6;
    	return 7;
    }
    
    int a[105],v[7],m[7],f[10][70],p[10];
    bool vis[10][70][2];//记忆化搜索是否访问过 
    ll dd[10][70][2];//存值 
    ll num(int now,int k,bool type)//now表示当前是第几个数字,a[now]为这个数字有几位 
    {//k表示分配的火柴数,type=1表示符号设置为正,取最大值,type=0表示符号为负,取最小值 
    	if(vis[a[now]][k][type]!=0)//记忆化搜索,否则会超时 
    	return dd[a[now]][k][type];
    	if(type)
    	{
    		mstn(f,250);//极小化 
    		f[0][0]=0;
    		FOR(i,1,a[now])//当前数字的第几位 
    		{
    			FOR(j,2,7)//第i个数字分配j根火柴 
    			FOR(t,0,k-j)
    			f[i][t+j]=max(f[i-1][t]+v[j]*p[a[now]-i],f[i][t+j]);
    		}
    	}
    	else
    	{
    		mstn(f,125);//极大化 
    		f[0][0]=0;
    		FOR(i,1,a[now])//当前数字的第几位 
    		{
    			FOR(j,2,7)//第i个数字分配j根火柴 
    			FOR(t,0,k-j)
    			{
    				if(i==1&&j==6)//排除前导零的干扰 
    				f[i][t+j]=min(f[i-1][t]+6*p[a[now]-i],f[i][t+j]);
    				else
    				f[i][t+j]=min(f[i-1][t]+m[j]*p[a[now]-i],f[i][t+j]);
    			}
    		}
    	}
    	vis[a[now]][k][type]=1;//表示访问过 
    	if(type)
    	{
    		dd[a[now]][k][type]=f[a[now]][k];
    		return f[a[now]][k];
    	}
    	else
    	{
    		dd[a[now]][k][type]=-f[a[now]][k];
    		return -f[a[now]][k];
    	}
    	
    }
    ll dp[105][705];
    int main()
    {
    	mst(vis);
    	v[2]=m[2]=1;//分别为使用2至7根火柴时取得的最大/小值 
    	v[3]=m[3]=7;
    	v[4]=m[4]=4;
    	v[5]=5,m[5]=2;
    	v[6]=9,m[6]=0;
    	v[7]=m[7]=8;
    	FOR(i,0,9) p[i]=pow(10,i);
    	int T,n,sum,cnt;
    	cin>>T;
    	string s;
    	while(T--)
    	{
    		mst(a);
    		sum=0;//一共有多少根火柴 
    		cnt=1;
    		cin>>n>>s;
    		FOR(i,0,n-1)
    		{
    			sum+=cal(s[i]);
    			if(s[i]=='+'||s[i]=='-')
    			cnt++;
    			else
    			a[cnt]++;
    		}
    		mstn(dp,250);//将dp值初始化为极小值,这是为了屏蔽不合法情况 
    		FOR(i,2*a[1],min(sum,7*a[1]))
    		dp[1][i]=num(1,i,1);//第一个数字默认为加号 
    		FOR(i,2,cnt)
    		{
    			FOR(k,0,sum)
    			{
    				FOR(j,2*a[i]+1,7*a[i]+2)//最小能分配的和最大能分配的 
    				{
    					if(k+j<=sum)
    					{
    						if(j!=2*a[i]+1)
    						dp[i][k+j]=max(dp[i][k+j],dp[i-1][k]+num(i,j-2,1));
    						if(j!=7*a[i]+2)
    						dp[i][k+j]=max(dp[i][k+j],dp[i-1][k]+num(i,j-1,0));
    					}
    					else
    					break;
    				}
    			}
    		}
    		cout<<dp[cnt][sum]<<endl;
    	}
    }
    

      

  • 相关阅读:
    【笔记】信息熵以及模拟使用信息熵来进行划分
    【笔记】决策树的基本思想及简单操作
    【笔记】SVM思想解决回归问题
    【笔记】核函数
    【笔记】sklearn中的SVM以及使用多项式特征以及核函数
    【笔记】浅谈支持向量机(SVM)
    灵雀云:etcd 集群运维实践
    灵雀云Kube-OVN进入CNCF沙箱,成为CNCF首个容器网络项目
    几张图解释明白 Kubernetes Ingress
    重大升级!灵雀云发布全栈云原生开放平台ACP 3.0
  • 原文地址:https://www.cnblogs.com/qq936584671/p/10742406.html
Copyright © 2020-2023  润新知