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;
} }