3 条题解

  • 1
    @ 2023-2-26 16:14:21
    备注:
    ******************************************/
    #include <queue>
    #include <math.h>
    #include <stack>
    #include <stdio.h>
    #include <iostream>
    #include <vector>
    #include <iomanip>
    #include <string.h>
    #include <algorithm>
    #include <map>
    using namespace std;
    #define int long long
    const int N = 1e3 + 10;
    const int INF = 0x3f3f3f3f;
    int n;
    int a[N];
    int dp[N][N][41];
    void calc(int t[], int s)
    {
    	int k = 0;
    	for(int i = 0; i < 40; i++)
    	{
    		t[i] = t[i] * s + k;
    		k = t[i] / 10;
    		t[i] %= 10;
    	}
    }
    void add(int t[], int dp[])
    {
    	for(int i = 0; i < 40; i++)
    	{
    		t[i] += dp[i];
    		t[i+1] += t[i] / 10;
    		t[i] %= 10;
    	}
    }
    bool cmp(int t[], int dp[])
    {
    	for(int i = 40; i >= 0; i--)
    	{
    		if(t[i] > dp[i])
    			return false;
    		else if(t[i] < dp[i])
    			return true;
    	}
    	return false;
    }
    void print(int dp[])
    {
    	int k = 40;
    	while(dp[k] == 0)
    		k--;
    	for(int i = k; i >= 0; i--)
    	{
    		cout << dp[i];
    	}
    	cout << endl;
    }
    signed main()
    {
    	//freopen(".in", "r", stdin);
    	//freopen(".out", "w", stdout);
    	cin >> n;
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> a[i];
    	}
    	for(int k = 3; k <= n; k++)
    	{
    		for(int l = 1; l <= n-k+1; l++)
    		{
    			int r = l+k-1;
    			dp[l][r][40] = 1;
    			for(int i = l+1; i < r; i++)
    			{
    				int t[41];
    				memset(t, 0, sizeof(t));
    				t[0] = 1;
    				calc(t, a[i]);
    				calc(t, a[l]);
    				calc(t, a[r]);
    				add(t, dp[l][i]);
    				add(t, dp[i][r]);
    				if(cmp(t, dp[l][r]))
    					memcpy(dp[l][r], t, sizeof(t));
    			}
    		}
    	}
    	print(dp[1][n]);
    	return 0;
    }
    
    
    • 1
      @ 2021-11-1 19:43:04

      多边形划分


      区间dp中仅次于石子合并的经典题, 区间dp的思想我应该不用细说了, 枚举断点,状态转移就完了


      题目做法

      让我们从一个三角形开始,乘就完了,这样能算出所有相邻三个点组成的三角形。

      然后是四边形,划分方法一共两种,定下两个点,要么这两个点和左边的点组成三角形,再加右边的三角形,要么反过来。我们已经算出了其中一个三角形,只要加上两个定点和选出的点组成的三角形即可。

      五边形也差不多,一共三种方法,你会发现,每种方法中除了选出的断点和两个定点组成的三角形以外,我们在前面的步骤中都已经算出来了。我们只要用左边加右边再算出中间就行。

      n边形的划分经过上面的推导,相信聪明的你已经想到办法了。 让我们枚举一个断点i

      dp[l][r]=dp[l][i]+dp[i][r]+中间三角形

      好,直接敲,自信提交,WA了

      请仔细阅读数据范围 每个点权值小于109\red{10^9}

      没错,这题还得加高精度。


      上代码

      //要是想高精度短点可以不维护长度,就是时间会多一点。
      #include <queue>
      #include <math.h>
      #include <stack>
      #include <stdio.h>
      #include <iostream>
      #include <vector>
      #include <iomanip>
      #include <string.h>
      #include <algorithm>
      #define LL long long
      #define IL inline
      const int N = 1e2+10;
      const int INF = 0x3f3f3f3f;
      using namespace std;
      int n,num[N][N],dp[N][N][N],sum[N],pre[N];//数组下表为0的数代表长度
      char s[20];
      IL int read()
      {
          char ch = getchar();
          int f = 1, num = 0;
          while(ch>'9'||ch<'0')
          {
              if(ch=='-') f = -1;
              ch=getchar();
          }
          while(ch>='0'&&ch<='9')
              num = num*10+ch-'0', ch = getchar();
          return num*f;
      }
      void print()
      {
          for(int i = dp[1][n][0];i>=1;i--)
              printf("%d",dp[1][n][i]);
          puts("");
      }
      void get(int id)//输入数组
      {
          num[id][0]=0;
          char ch=getchar();
          while(ch>'9'||ch<'0')
              ch=getchar();
          while(ch>='0'&&ch<='9')
              s[++num[id][0]]=ch,ch=getchar();
          for(int i = 1,j=num[id][0];i<=num[id][0];i++,j--)
              num[id][i]=s[j]-'0';
      }
      void push(int opt)//更新长度
      {
          if(opt)   
              while(sum[sum[0]+1]) sum[0]++;
          else   
              while(pre[pre[0]+1]) pre[0]++;
      }
      void Mul(int l,int k,int r)//为了主程序简洁点干脆全写一起了
      {
          memset(pre,0,sizeof(pre));
          memset(sum,0,sizeof(sum));
          pre[0]=num[l][0]+num[r][0]-1;
          for(int i = 1;i<=num[l][0];i++)
              for(int j = 1;j<=num[r][0];j++)
              {
                  pre[i+j-1]+=num[l][i]*num[r][j];
                  pre[i+j]+=pre[i+j-1]/10;
                  pre[i+j-1]%=10;
              }
          push(0);
          sum[0]=pre[0]+num[k][0]-1;
          for(int i = 1;i<=pre[0];i++)
              for(int j = 1;j<=num[k][0];j++)
              {
                  sum[i+j-1]+=pre[i]*num[k][j];
                  sum[i+j]+=sum[i+j-1]/10;
                  sum[j+i-1]%=10;
              }
          push(1);
      }
      void Add(int l,int i,int r)//懒得加两次
      {
          sum[0]=max(sum[0],max(dp[l][i][0],dp[i][r][0]));
          for(int k = 1;k<=sum[0];k++)
          {
              sum[k]+=dp[l][i][k]+dp[i][r][k];
              sum[k+1]+=sum[k]/10;
              sum[k]%=10;
          }
          push(1);
      }
      bool Com(int l,int r)//比较
      {
          if(!dp[l][r][0]) return true;
          if(sum[0]!=dp[l][r][0]) return sum[0]<dp[l][r][0];
          for(int i = sum[0];i>=1;i--)
              if(sum[i]>dp[l][r][i])
                  return false;
              else if(sum[i]<dp[l][r][i])
                  return true;
          return false;
      }
      void calc(int l,int r,int i)
      {
          Mul(l,i,r);
          Add(l,i,r);
          if(Com(l,r))
              memcpy(dp[l][r],sum,sizeof(dp[l][r]));
      }
      int main()
      {
          n=read();
          for(int i = 1;i<=n;i++)
              get(i);
      
          for(int k = 2;k<=n-1;k++)
              for(int l = 1,r=l+k;r<=n;l++,r++)
                  for(int i = l+1;i<=r-1;i++)
                      calc(l,r,i);
          print();
      }
      

      A完之后看别人代码,好家伙我高精度也太长了。

      • 0
        @ 2023-3-11 10:32:39
        备注:
        ******************************************/
        #include <queue>
        #include <math.h>
        #include <stack>
        #include <stdio.h>
        #include <iostream>
        #include <vector>
        #include <iomanip>
        #include <string.h>
        #include <algorithm>
        #include <map>
        using namespace std;
        #define int long long
        const int N = 1e3 + 10;
        const int INF = 0x3f3f3f3f;
        int n;
        int a[N];
        int dp[N][N][41];
        void calc(int t[], int s)
        {
        int k = 0;
        for(int i = 0; i < 40; i++)
        {
        t[i] = t[i] * s + k;
        k = t[i] / 10;
        t[i] %= 10;
        }
        }
        void add(int t[], int dp[])
        {
        for(int i = 0; i < 40; i++)
        {
        t[i] += dp[i];
        t[i+1] += t[i] / 10;
        t[i] %= 10;
        }
        }
        bool cmp(int t[], int dp[])
        {
        for(int i = 40; i >= 0; i--)
        {
        if(t[i] > dp[i])
        return false;
        else if(t[i] < dp[i])
        return true;
        }
        return false;
        }
        void print(int dp[])
        {
        int k = 40;
        while(dp[k] == 0)
        k--;
        for(int i = k; i >= 0; i--)
        {
        cout << dp[i];
        }
        cout << endl;
        }
        signed main()
        {
        //freopen(".in", "r", stdin);
        //freopen(".out", "w", stdout);
        cin >> n;
        for(int i = 1; i <= n; i++)
        {
        cin >> a[i];
        }
        for(int k = 3; k <= n; k++)
        {
        for(int l = 1; l <= n-k+1; l++)
        {
        int r = l+k-1;
        dp[l][r][40] = 1;
        for(int i = l+1; i < r; i++)
        {
        int t[41];
        memset(t, 0, sizeof(t));
        t[0] = 1;
        calc(t, a[i]);
        calc(t, a[l]);
        calc(t, a[r]);
        add(t, dp[l][i]);
        add(t, dp[i][r]);
        if(cmp(t, dp[l][r]))
        memcpy(dp[l][r], t, sizeof(t));
        }
        }
        }
        print(dp[1][n]);
        return 0;
        }
        
        • 1

        信息

        ID
        468
        时间
        1000ms
        内存
        512MiB
        难度
        6
        标签
        递交数
        181
        已通过
        61
        上传者