import java.util.Scanner;java
/**算法
@Author LZP测试
@Date 2021/2/17 16:18code
@Version 1.0递归
动态规划内存
试题 算法训练 Sereja and Squares资源
资源限制字符串
时间限制:4.0s 内存限制:256.0MBinput
问题描述it
Sereja在平面上画了n个点,点i在坐标(i,0)。而后,Sereja给每一个点标上了一个小写或大写英文字母。Sereja不喜欢字母"x",因此他不用它标记点。Sereja认为这些点是漂亮的,当且仅当:
·全部的点能够被分红若干对,使得每一个点刚好属于一一对之中。
·在每对点中,横坐标较小的会被标上小写字母,较大的会被标上对应的大写字母。
·若是咱们在每对点上画一个正方形,其中已知的一对点会做为正方形的相对的顶点,它们间的线段会成为正方形的对角线,那么在全部画出的正方形中不会有相交或触碰的状况。
小Petya擦掉了一些小写字母和全部大写字母,如今Sereja想知道有多少种方法来还原每一个点上的字母,使得还原后这些点是漂亮的。
输入格式
第一行是一个整数n,表示点的个数。
第二行是一个长度为n的字符串,包含小写字母和问号"?",是按照横坐标递增的顺序的每一个点的描述。问号表示这个点的字母被Petya擦掉了。保证输入串不含字母"x"。
输出格式
输出答案对4294967296取模的值。若是没有可行的方案,输出0。
样例输入
4
a???
样例输出
50
样例输入
4
abc?
样例输出
0
样例输入
6
abc???
样例输出
1
数据规模和约定
20个测试点的n分别为:
5,10,20,50,100,
200,500,1000,2000,5000,
10000,20000,30000,40000,50000,
60000,70000,80000,90000,100000.
递归实现:
不过效率过低
使用栈,将其看成左右括号匹配的问题来实现,这是本题的重要解题思路
本题适合用C++写,C++的效率比Java高太多了
*/
public class Main2 {
private static long num = 0;
private static long mod = 4294967296L;
private static char[] arr = new char[100000 + 7];
private static long[] dp = new long[100000 + 7];
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
char[] tempChar = input.next().toCharArray();
for (int i = 0; i < tempChar.length; i++) {
arr[i + 1] = tempChar[i];
}
// 没有右括号 ,这一步必定不能漏 dp[0] = 1; long start = System.currentTimeMillis(); f(arr, n); long end = System.currentTimeMillis(); System.out.println(num); System.out.println(end - start + "ms");
}
static void f(char[] arr, int n) {
if (n % 2 == 1) {
// 奇数直接返回
return;
}
// 用来记录左括号的个数 int left = 0; int n2 = n >> 1; // 循环从1~n for (int i = 1; i <= n; i++) { if (arr[i] == '?') { // 如果问好,则多是左括号也多是右括号 // 肯定右括号的最大上限 int rightMax = i >> 1; if (i != n) { /* 当dp到下标i时,能够肯定的最多的右括号为i/2, 若如今肯定的是左括号则前面i-1个格子就是肯定rightMax个右括号的结果 若如今肯定的是右括号,则前面i-1个格子肯定的就是rightMax-1个右括号的结果 */ // 由于只是肯定了右括号的最大上限,而不肯定究竟是多少,因此有不少种可能 // 每次后面多来一个右括号的话,前面的可能性就越多 for (; rightMax >= 1; rightMax--) { dp[rightMax] += dp[rightMax - 1]; dp[rightMax] %= mod; } } else { //i==n必定是右括号,只要肯定前n-1个格子所肯定出来的n>>1-1个右括号的结果便可 dp[rightMax] = dp[rightMax - 1]; dp[rightMax] %= mod; } } else { // 若不是问好,则必定是左括号 left++; } } if (left > n2) { // 左括号的个数超过一半 return; } for (int i = 0; i < n2 - left; i++) { dp[n2] *= 25; dp[n2] %= mod; } num = dp[n2] % mod;
} }