題目大意: 給定n個文件夾,每個文件夾有若干tag和一個size。再給出m個查詢,查詢也是若干個tag,要求找出這些tag在n個文件夾中的哪些裡面出現,可以無視tag的順尋,凡出現的都把size加起來,然後輸出。
解題思路:用bitset和map能很輕松地解決,用個map記錄每個tag在哪些文件夾中出現,map<string,bitset<1024> >(4>和>之間要有個'_'),表示1024個文件夾哪個包含這個string,然後查詢的時候就只要看哪個文件夾包含了所有tag,也就是這些tag對應的bitset值&起來,到最後是true的那個文件夾就要把size累加起來。
先來看看百度百科上對bitset的一些介紹:
[cpp]
#include <bitset>
bitset //有三種聲明方式在缺省定義中我們只需簡單地指明位向量的長度例如
bitset< 32 > bitvec; //聲明了一個含有32 個位的bitset 對象位的順序從0 到31 缺省情況下所有的位都被
//對象的一位或多個位被設置為1 時any()返回true 對於bitvec .如下測試
bool is_set = bitvec.any(); //它的結果當然是false 相反如果bitset 對象的所有位都被設置為0 ,則none()操作返回
bool is_not_set = bitvec.none();//結果為true count()操作返回被設置為1 的位的個數.
int bits_set = bitvec.count(); //我們可以用set()操作或者下標操作符來設置某個單獨的位例如下面的for 循環把偶數位設置為1.
for ( int index = 0; index < 32; ++ index )
if ( index % 2 == 0 )
bitvec[ index ] = 1; //類似地測試某個單獨的位是否為1 也有兩種方式test()操作用位置做參數返回true
if ( bitvec.test( 0 )) // 我們的bitve[0] 可以工作了! 同樣地我們也可以用下標操作符
for ( int index = 0; index < 32; ++index )
if ( bitvec[ index ] )
cout << index << " "; cout << endl;
bitvec.reset( 0 );
bitvec[ 0 ] = 0;
//我們也可以用set()和reset()操作將整個bitset 對象的所有位設為1 或0 ,只要調用相應的操作而不必傳遞位置參數我們就可以做到這一點.例如
bitvec.reset();
if ( bitvec.none() != true )
//flip()操作翻轉整個bitset 對象或一個獨立的位
bitvec.flip( 0 ); // 翻轉第一位
bitvec[0].flip(); // 也是翻轉第一位
bitvec.flip(); // 翻轉所有的位的值
//還有兩種方法可以構造bitset 對象它們都提供了將某位初始化為1 的方式:一種方法是為構造函數顯式地提供一個無符號參數bitset 對象的前N 位被初始化為參數的相應位值,例如
bitset< 32 > bitvec2( 0xffff );
//將bitvec2 的低16 位設為1
00000000000000001111111111111111
//下面的bitvec3 的定義
bitset< 32 > bitvec3( 012 );
//將第1 和3 位的值設置為1 假設位置從0 開始計數
00000000000000000000000000001010
//我們還可以傳遞一個代表0 和1 的集合的字符串參數來構造bitset 對象如下所示
// 與bitvec3 的初始化等價
string bitval( "1010" );
bitset< 32 > bitvec4( bitval );
//bitvec4 和bitvec3 的第1 和3 位都被設置為1 而其他位保持為0
bitvec.set()
看完這些,在對照著題目和代碼,就會發現用bitset還是相當飄逸的。
測試數據:
5
[comic][naruto][01] 1024
[comic][naruto][02] 1024
[comic][inuyasha][01] 1024
[comic][inuyasha][02] 1024
[comic][inuyasha][03] 1024
3
[inuyasha]
[comic][01]
[ost]
Out: 3072 \n 2047\n 0\n
代碼:
[cpp]
<span style="color:#ff0000;">#include <cstdio>
#include <map>
#include <string>
#include <cstring>
#include <bitset>
#include <vector>
using namespace std;
#define int64 long long
#define MAX 1300
int64 n,m,size[MAX],ans;
bitset<MAX> mask; //mask表示該串出現在哪些主串中
char str[1<<17],*p,*q;
map<string,bitset<MAX> > mmap; //表示i=0...n-1內哪些串含有string子串
map<string,bitset<MAX> >::iterator it; //迭代器
int main()
{
int i,j,k;
while (scanf("%lld",&n) != EOF) {
ans = 0;
mmap.clear();
for (i = 0; i < n; ++i) {
scanf("%s %lld",str,&size[i]);
p = str; //把首地址付給p指針
while ((p = strchr(p,'[')) != NULL) { //從p開始找第一個'[',如果沒有返回NULL
q = strchr(p,']');
string tp = string(p+1,q); //構造函數tp = str[p+1........q-1]
mmap[tp].set(i); //第i個串含有tp
p = q; //從q開始才不至於無限循環
}
}
scanf("%lld",&m);
for (i = 0; i < m; ++i) {
scanf("%s",str);
for (j = 0; j < n; ++j)
mask.set(j); //相當於memset(true)
p = str;
while ((p = strchr(p,'[')) != NULL) {
q = strchr(p,']');
string tp = string(p+1,q);
it = mmap.find(tp); //相當於mmap[tp]
if (it == mmap.end()) {
mask.reset();
break;
}
else mask &= it->second; //如果it裡都有某位,則最後該子串必定包含在那個主串中
p = q;
}
ans = 0;
for (j = 0; j < n; ++j)
if (mask[j]) ans += size[j];
printf("%lld\n",ans);
}
}
}</span>