ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

蓝桥杯---Sereja and Squares

2021-03-27 21:00:37  阅读:229  来源: 互联网

标签:--- 题目 int Sereja 蓝桥 括号 我们 dp


题目链接在这里~
问题描述
  Sereja在平面上画了n个点,点i在坐标(i,0)。然后,Sereja给每个点标上了一个小写或大写英文字母。Sereja不喜欢字母"x",所以他不用它标记点。Sereja认为这些点是漂亮的,当且仅当:
  ·所有的点可以被分成若干对,使得每个点恰好属于一一对之中。
  ·在每对点中,横坐标较小的会被标上小写字母,较大的会被标上对应的大写字母。
  ·如果我们在每对点上画一个正方形,其中已知的一对点会作为正方形的相对的顶点,它们间的线段会成为正方形的对角线,那么在所有画出的正方形中不会有相交或触碰的情况。
  小Petya擦掉了一些小写字母和所有大写字母,现在Sereja想知道有多少种方法来还原每个点上的字母,使得还原后这些点是漂亮的。
思路
  看到题目的时候有点蒙,看了一些别人的想法觉得真的太聪明了,这个题目可以等价为括号的配对问题,只不过这里的括号不是一种,而是25种(a-z,除去x),这样看的话,这道题会变得好懂一点,这个题目真是晦涩得很
 大致的心路历程是这样的:
 first,当n为奇数时,因为是配对问题嘛,奇数自然是不符合的了,直接输出0即可。
 second,当n为偶数时,我们可以先忽略掉括号的种类,将其看做只有一种类型的普通括号配对。
 我们要知道的是,题目中说:擦去了大写字母及部分小写字母,翻译一下就是,我们现在有的是一部分左括号,我们要加上一些左括号及右括号使其配对。这里用到了动态规划(说实话,我开始想不到这道题怎么写动态规划方程,甚至不知道dp[i][j]要代表什么。。maybe多练几道可以懂得多一点吧),所以我看了别人的题解(当然,学会别人的思路也是一种进步~)
 dp[i][j]:在确定的前i个字符里有j个右括号的情况数
 然后我们要考虑的是,状态转移方程:
 在前一种情况已知的情况下,再加一个字符的情况:也就是
 dp[i][j]=dp[i-1][j]+dp[i-1][j-1],当前加的可以是左或右。若当前为左,那dp[i][j]就是dp[i-1][j]转化来的(前i-1个确定的字符有j个右括号);若当前为右,那dp[i][j]就是由dp[i-1][j-1]转化来的(前i-1个字符有j-1个右括号,因为一共j个,第i位占了一个)
 其实这里还算好想,至少可以看懂,我理解了好久的地方就是那个循环:
 for(int j=i/2;j>=i-m&&j;j--)
i呢,控制的是前多少个字符,自然就是1-n,这很好理解,那么j呢?
j是代表前i个字符有几个右括号,为了配对,一共i个,那右括号最多i/2个(i为偶数时,对半分,i为奇数时,多一个左括号,符合题意),那下限用什么呢?0嘛?其实要这么想:现在一共i个,而左括号最多n/2个,那右括号最少就是i-n/2,(当然,这样可能会小于0,所以还要保证他大于0)
状态转移方程到这里就差不多了,接下来一个问题就是内存空间,因为给的测试样例最大是100000,dp[i][j]会太大,所以我们要考虑压缩空间,这个方法我也是第一次学到:滚动数组
大概就是:因为我们每一位都是要依赖前一位,也只依赖前一位,所以我们可以用一维数组来存放,每次用后一位覆盖前一位,达到节省空间的效果,这样的话,我们的状态转移方程就变成了:dp[j]=dp[j]+dp[j-1],循环利用
现在的话空间问题也解决了,最后就是要考虑括号的种类问题,因为我们刚才忽略了括号的种类,现在要重新加上,在刚才的基础上,我们得到了dp[n/2],(当然i循环到了n),也就是n位字符中n/2个j的情况数。这时也就有n/2个左括号,我们可以这样想,右括号是由左括号决定的,而左括号有几个是题目给的,所以我们能决定的就是新增的几个,每一位都有25种选择,这样就得到了最终的结果。
好了,思路应该理得差不多,我们来看代码

#include <bits/stdc++.h>

using namespace std;

int main()
{

   int n;
   cin>>n;
   unsigned int f[n];
   char str[n+1];
   cin>>str+1;
   if(n%2==1)
   {
       cout<<0<<endl;
   }
   else
   {
       int cnt=1;
       int ans=0;
       int m=n/2;
       for(int i=1;i<=m;i++)
       {
           f[i]=0;
       }
       f[0]=1;
       for(int i=1;i<=n;i++)
       {
           if(str[i]=='?')
           {
               for(int j=i/2;j>=i-m&&j;j--)
               {
                   f[j]+=f[j-1];
               }
           }
           else
               ans++;
       }
       for(int i=0;i<m-ans;i++)
           cnt*=25;
       cout<<f[m]*cnt%4294967296<<endl;

   }

   return 0;
}

标签:---,题目,int,Sereja,蓝桥,括号,我们,dp
来源: https://blog.csdn.net/qq_51052824/article/details/115270505

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有