AtCoder Grand Contest #026 C - String Coloring
Time Limit: 3 sec / Memory Limit: 1024 MB
Score : 600600 points
Problem Statement
You are given a string SS of length 2N2N consisting of lowercase English letters.
There are 22N22N ways to color each character in SS red or blue. Among these ways, how many satisfy the following condition?
- The string obtained by reading the characters painted red from left to right
Constraints
- 1≤N≤181≤N≤18
- The length of SS is 2N2N.
- SS consists of lowercase English letters.
Input
Input is given from Standard Input in the following format:
NN SS
Output
Print the number of ways to paint the string that satisfy the condition.
Sample Input 1 Copy
Copy4 cabaacba
Sample Output 1 Copy
Copy4
There are four ways to paint the string, as follows:
- cabaacba
- cabaacba
- cabaacba
- cabaacba
Sample Input 2 Copy
Copy11 mippiisssisssiipsspiim
Sample Output 2 Copy
Copy504
Sample Input 3 Copy
Copy4 abcdefgh
Sample Output 3 Copy
Copy0
Sample Input 4 Copy
Copy18 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Sample Output 4 Copy
Copy9075135300
The answer may not be representable as a 3232-bit integer.
如果直接暴力是O(2^2n)的復雜度,肯定超時,測試樣例就可以直接測試出超時i,所以要縮短復雜度,這道題很巧妙,可以把字符串分為兩半,這樣復雜度就是O(2^n)的了,為什麽要分為兩部分呢?
先回到題目要求,題目要求就是把字符串分為相等的兩個字符串(當然不是從中部分開),一部分從左往右選取n個,一部分從右往左選取n個,這兩個字符串相等。
對照第一個樣例,可以設這兩個字符串為a(紅色)和ra(藍色),把原字符串從中部分開,左邊包含藍色和紅色,右邊也包含藍色和紅色,a和ra(倒序選取的)是相等的,所以a在左邊的部分等於ra在右邊的部分,a在右邊的部分等於ra在左邊的部分,caba acba,a的左邊部分是"c",ra的右邊部分也是"c",a的右邊部分是"aba",ra的左邊部分也是"aba",其實很好想象,如果存在a和ra相等,那麽一定滿足這個規律,左右兩半的長度都為n,a和ra的長度也為n,如果a在左邊的長度as(<=n),那麽左邊剩下的(n - as)個字符組成的反向字符串肯定是和a在右邊的剩余部分相等的,首先長度肯定是相等,其次內容,因為a和ra都是按照順序選取並組合的字符串,所以內容肯定也是相等的。因此可以建立一個狀態pair<a,ra>,左右狀態是相同的就是滿足的。
這樣只需要記錄左邊的狀態,狀態相同的算到一起,紅色和藍色的順序是無關的,比如caaa acaa和caaa acaa,左邊狀態是相同的,所以再看右部遇到狀態相同的,只需要加上左邊相同狀態的個數就可以了,遍歷直接按照二進制位計算就可以了,區間[0,1<<n)。
c++代碼:
#include <map> #include <iostream> using namespace std; typedef pair<string,string> pa; int main() { int n; long long ans = 0; string s; map<pa,int> mp; cin>>n>>s; for(int i = 0;i < 1 << n;i ++) { string a = ""; string b = ""; for(int j = 0;j < n;j ++) { if(i >> j & 1)a += s[j];///二進制位為1 屬於a串 else b += s[j];///二進制位為0 屬於ra串 } mp[pa(a,b)] ++;///記錄狀態個數 } for(int i = 0;i < 1 << n;i ++) { string a = ""; string b = ""; for(int j = 0;j < n;j ++) { if(i >> j & 1)a += s[n * 2 - 1 - j];///二進制位為1 屬於a串 else b += s[n * 2 - 1 - j];///二進制位為0 屬於ra串 } ans += mp[pa(a,b)];///加上匹配的狀態個數 } cout<<ans; }
java代碼:
import java.util.*; class Pair<V,K>{ V first; K second; public Pair() {first = null;second = null;} public Pair(V f,K s){ first = f; second = s; } public boolean equals(Object o) { if(!(o instanceof Pair)) { return false; } Pair<V,K> pn = (Pair<V,K>)o; return pn.first.equals(first) && pn.second.equals(second); } public int hashCode() { return first.hashCode() + second.hashCode(); } } public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); long ans = 0; int n = in.nextInt(); String s = in.next(); String aa = null,bb = null; Map<Pair<String,String>,Integer> map = new HashMap(); for(int i = 0;i < 1 << n;i ++) { StringBuilder a = new StringBuilder(); StringBuilder b = new StringBuilder(); for(int j = 0;j < n;j ++) { if((i >> j) % 2 == 1)a.append(s.charAt(j)); else b.append(s.charAt(j)); } aa = a.toString(); bb = b.toString(); if(map.containsKey(new Pair(aa,bb)))map.put(new Pair(aa,bb),map.get(new Pair(aa,bb)) + 1); else map.put(new Pair(aa,bb),1); } for(int i = 0;i < 1 << n;i ++) { StringBuilder a = new StringBuilder(); StringBuilder b = new StringBuilder(); for(int j = 0;j < n;j ++) { if((i >> j) % 2 == 1)a.append(s.charAt(n * 2 - 1 - j)); else b.append(s.charAt(n * 2 - 1 - j)); } aa = a.toString(); bb = b.toString(); if(map.containsKey(new Pair(aa,bb)))ans += map.get(new Pair(aa,bb)); } System.out.println(ans); } }
AtCoder Grand Contest #026 C - String Coloring