Codeforces round 396(Div. 2) 题解
Problem A
題目大意
給定兩個字符串,要求構造出一個最長的一個串滿足:這個串是其中一個串的字序列并且不是另一個串的子序列.輸出長度.\((len \leq 10^5)\)
題解
千萬年死在讀題上
我做題的時候:哇!這不是一道SB題嘛?
2mins敲完,提交Wrong answer
我去,好像看錯題了。。我說怎么這道題這么二。。。
我重新看了眼題。。
那這題不更SB了嗎??????
一邊懷疑自己一邊提交了上去,結果Accepted了。。
我去,判個字符串是否相等,再輸出長度最大值就可以了
Problem B
題目大意
給定一個長為n的序列,判斷是否能從這個序列中選出三個數使得這三個數可以組成一個三角形的三邊長。\((n \leq 10^5)\)
題解
暴力枚舉肯定不可行。
所以我們要有智商地枚舉。
我們發現我們其實就是要在這里面選出三個數\(a,b,c\)滿足
\(a+b > c ; a+c > b ; b+c > a\)
我們設\(a,b,c\)中最大值為\(a\),那么我們就發現\(a+b < c,a+c < b\)都一定成立
所以我們再選出兩個小于等于\(a\)值滿足\(b+c < a\)即可
所以我們直接對輸入序列排序,順序考慮\(a\)的取值
取第一個\(\leq a\)和第二個\(\leq a\)的值作為\(b,c\)判定即可
Problem C
題目大意
分別規定\(26\)個字母中每個字母所在的字符串長度不能超過某一值,給定一個長為\(n\)的字符串,將其劃分成一些子串,使這個字符串滿足上述要求。求:方案數\((mod \text{ } 10^9 + 7)\)、可行劃分方案中的最長字串長度、最少劃分成多少字串。\((ln \leq 10^5)\)
題解
又是一道字符串。。。
我們看到求方案數+取模就知道這一般不是一道數論題就是一道dp題
我們又看到了這數據范圍就可以確定這是一個dp了
我們設\(f[i]\)表示成功劃分了\(1~i\)的字符串的方案數,然后我們枚舉\(j \in [0,i-1]\)轉移即可。
第二問、第三問可以在算方案數的過程中直接記錄或用類似過程計算
//沒取模掛掉一次
Problem D
題目大意
給定n個詞的含義相同或相反的共m個關系,關系具有傳遞性.每次給定關系的時候先判斷此關系是否可以由前面的關系判斷,如果不可以則添加此關系,否則判斷此關系是否與推斷出來的相符。最后詢問q組詞之間的關系。\((n,m,q \leq 10^5)\)
題解
一看這套路就知道是帶權并查集。
每個節點維護父系指針和與父親的關系。
我們把相反記為1,相同記為0.
每次判斷亮點關系時只需要判斷一下兩點父親是否相同
若父親相同則可以推斷兩點的官司
若兩點與父親的關系均相同或均相反,則兩點的關系為相同,否則為相反
至于關系的傳遞性嘛。。我們發現這個關系的傳遞性恰好是\(xor\)也就是異或
即\(num_{a->c} = num_{a->b}\text{ } xor \text{ }num_{b->c}\),其中\(num_{a->b}\)表示\(a,b\)的關系.
所以我們可以簡單地完成路徑壓縮和查詢。
竟然卡我的\(map!!!\)手寫了顆\(Trie\)才過的...
#include <map> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; inline void read(int &x){x=0;char ch;bool flag = false;while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x; } const int maxn = 100010; int fa[maxn],num[maxn]; inline int find(int x){int f = x;while(f != fa[f]) f = fa[f];int y = fa[x],z;while(y != f){z = fa[x];while(z != f){num[x] ^= num[z];z = fa[z];}fa[x] = f;x = y;y = fa[x];}return f; } const int maxnode = maxn*22 + 10; int ch[maxnode][27],idx[maxnode],nodecnt; inline void insert(int x){char c;while(c = getchar(),c<'!');int nw = 0;while(c >= 'a' && c <= 'z'){if(ch[nw][c - 'a'] == 0) ch[nw][c - 'a'] = ++nodecnt;nw = ch[nw][c - 'a'];c = getchar();}idx[nw] = x; } inline int query(){char c;while(c = getchar(),c<'!');int nw = 0;while(c >= 'a' && c <= 'z'){nw = ch[nw][c - 'a'];c = getchar();}return idx[nw]; } int main(){int n,m,q;read(n);read(m);read(q);for(int i=1;i<=n;++i){insert(i);fa[i] = i;}for(int i=1,c;i<=m;++i){read(c);--c;int x = query();int y = query();//printf("linking %d %d\n",x,y);int fx = find(x);int fy = find(y);if(fx == fy){if( (c == 0) == (num[x] == num[y]) ) puts("YES");if( (c == 0) != (num[x] == num[y]) ) puts("NO");}else{fa[fx] = fy;if(num[x]^num[y] == c) num[fx] = 0;else num[fx] = 1;puts("YES");}}while(q--){int x = query();int y = query();int fx = find(x);int fy = find(y);if(fx != fy) puts("3");else printf("%d\n",(num[x] != num[y]) + 1);}getchar();getchar();return 0; }Problen E
題目大意
給定一顆點有點權\((val_i \leq 10^6)\)的n個節點的樹,定義兩點距離為路徑上點權異或和。求所有無序點對之間的距離之和。\((n \leq 10^5)\)
題解
因為這道題是對二進制數位進行操作
常規方法不好做的時候應該自然而然地想到對每個數位分別討論。
我們發現:把每個數位拆開之后,所有的點權都變成了0/1
然后我們要統計的就是xor后為1的數對的個數
我們考慮樹形dp
設\(f[i][j]\)表示以i為根的子樹中到達點i時xor后得到j的節點數目.
即j是0或1
然后我們\(O(n)\)一遍可以算出所有點向上的貢獻.
我們再\(dfs\)一遍算出所有點向下的貢獻即可.
在vjudge上做完這些題后去codeforces開了Virtual participation,4分鐘AC五道題,真爽!
轉載于:https://www.cnblogs.com/Skyminer/p/6395198.html
總結
以上是生活随笔為你收集整理的Codeforces round 396(Div. 2) 题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: stein法求gcd 学习笔记
- 下一篇: 利用Axis2默认口令安全漏洞入侵Web