題意:
給你n個字串,讓你在裡面找到乙個字串集合使得這些字串中所有的字母出現的次數和為偶數,輸出集合的最大個數,和ascii最小的解。
思路:考慮到每個字串中所有的字元都是有大寫字母組成的,我們可以把每個字串都用乙個26位長的二進位制數表示,比如第一位表示a,那麼當第一位為0的時候就是說明a出現了偶數次,1表示出現了奇數次(直接異或),那麼我們要找到滿足題意的集合也就是可以轉化成我們在n個26位長的二進位制數中找到最多的數字,使得他們異或一起最後等於0(等於0表示所有的字母都是偶數次),這樣我們有兩種方式,一種是我自己寫的暴搜,時間複雜度o(2^n)沒有超時,如果是要完全的暴力建議去寫搜尋,不要寫for迴圈列舉,因為for的列舉在判斷的時候時間複雜度還要*n,這樣估計就超時了,寫搜尋可以在狀態轉換的時候把值算出來,這樣最後的時候不用可以去算什麼,直接if判斷,減少了乙個n,時間複雜度應該是妥妥的o(2^n),還有就是再說下白書上的方法,用的是中途相遇法,這個方法感覺很好,讓我想起了雙向廣搜,這個題目我想是不是應該叫雙向深搜,大體思路就是把要列舉的東西分成兩部分分別列舉,然後在結合一起去判斷,時間複雜度可以降低不少,白書給的時間複雜度我感覺算的有問題,我算的是o(1.44^n*n/2),兩個方法我都試了,中途相遇法的時間複雜度優化了很多,下面是兩個方法的ac**。
直接暴力深搜 時間複雜度
o(2^n) runtime 2.292
#include
#include
#include
#include
using namespace std;
int num[30];
char str[1100];
int ans ,anszt;
void dfs(int nowid ,int nows ,int nownum ,int nowzt)
}return ;
}dfs(nowid - 1 ,nows ,nownum ,nowzt * 2);
dfs(nowid - 1 ,nows + 1 ,nownum ^ num[nowid] ,nowzt * 2 + 1);
}int main ()
ans = anszt = 0;
dfs(n ,0 ,0 ,0);
printf("%d\n" ,ans);
int nowid = 1 ,mk = 0;
while(anszt)
anszt /= 2;
nowid ++;
}printf("\n");
}return 0;
}中途相遇法 時間複雜度
o(2^(n/2)*n/2) => 1.44^n*n/2 runtime 0.029
#include
#include
#include
#include
using namespace std;
mapmark;
int num[30];
char str[1100];
int bitcount(int x)
int main ()
mark.clear();
int n1 = n / 2;
int n2 = n - n1;
for(i = 0 ;i < (1 << n1) ;i ++)
int ans = 0;
for(i = 0 ;i < (1< bitcount(ans))
ans = (i << n1) ^ mark[x];
}printf("%d\n" ,bitcount(ans));
int mk = 0,anszt = ans ,nowid = 1;
while(anszt)
anszt /= 2;
nowid ++;
}printf("\n");
}return 0;
}
LA 2965 中途相遇法
題意 有很多字串 24 選出一些字串,要求這些字串的字母都是偶數次 分析 暴力2 24也很大了,中途相遇法 其原理就是一分為二,兩組解組成問題的解 考慮到,每個字串出現的次數沒什麼關係,只要關於他的奇偶,那麼就有二進位制,1出現奇數次,0偶數次 每乙個字串對應於乙個a位向量,在前半個表中,選擇一些字...
LA2965字串合併
la2965 題目描述 給定n個大寫字母組成的連續字串,n 24 選取其中的m個組合,使相同的大寫字母的出現次數之和為偶數。目標是讓這個m最大。演算法分析 ps 這道題看著比較簡單,但是編碼有難度。中途相遇法 首先,如果將每種狀態用位表示,就是2 24種狀態,1表示奇數個,0表示偶數個。利用異或運算...
異或和之和 異或問題
題目 有n個數,任選3個進行異或,求出所有三元組的異或和的和 普通計算是 o n 3 但是發現,對於異或的運算,就轉換為二進位制的運算,把每乙個陣列轉換為二進位制,再拆分,當且僅當 1 1 1 和 1 0 0 時,答案才為1,否則都是0,也就是說,只有這兩個情況是由貢獻的 把每個數位化為二進位制,然...