這次比賽比較簡單,然而t1太自信結果炸了,t3腦子壞掉又寫錯了,真是沒辦法啊,分數就白白丟掉了好多。。
乙個匹配模式是由一些小寫字母和問號』?』組成的乙個字串。當乙個由小寫字母組成的字串s,長度和匹配模式長度相同,並且在對應的每一位都相等或模式串相應位置是『?』,則稱字串s與這個模式相匹配。例如:」abc」與」a?c」匹配地,但不與」a?b」或」abc?」相匹配。
現給你 m 個匹配模式,它們長度相同,問恰好與其中有 k 個模式相匹配的字串有多少個?(答案模1,000,003)
第一行,兩個整數 m k。
下面有m行字串,表示m個匹配模式。
1<= m <= 15
模式長度len滿足:1 <= len<= 50
1 <= k <=m
模式中只含小寫英文本母和 『?』
只一行,乙個整數(模1000003之後)。
樣例1:
2 2樣例2a? ?b
1 1樣例1: 樣例2:?????
881343這題可以用很暴力的狀壓dp切掉,但是優美的方法是容斥原理。(注:881343 = 26^5 mod 1000003。)
就是那個被大佬們成為廣義容斥原理的東東。
首先注意題目求的是恰好k個匹配。我們列舉出所有狀態,然後看看有幾個匹配,假如有k個匹配就加進答案。但是可能匹配有多,假如匹配了k+1個就要減,但是減多了k+2的加回來。於是就是乙個容斥原理了。
但是廣義在於**呢?一開始我錯了,原因在於假如匹配了k+1的方案數,對k答案的貢獻是要被減去的,但減去可不止乙個!設方案為v,次數就是ck
k+1 ,於是當前匹配了p個模式,貢獻就是ck
p∗v∗
sign
。其中當p-k為偶數時sign=1。當然p
<
k不做。剩下的一堆就是細節的處理,具體是怎樣算出v,這個很簡單,看看有無矛盾,統計?個數就行了。
預處理出組合數會更好。我一開始80分因為取模的時候,可能是負數取模,忘了模數再取模了!qaq!
時間一點也不複雜。
#include
#include
#include
#include
#include
#include
#define maxm 20
#define maxl 60
#define mods 1000003
using
namespace
std;
int m, k, ans;
int len[maxm];
int c[maxm][maxm];
char s[maxm][maxl], cc[maxl];
bool vis[maxm];
void da()
}int main()
for(int i = 1; i < (1
for(int j = 1; j <= m; j++) vis[j] = false;
while(temp)
temp >>= 1;
b ++;
}if(cnt < k) continue;
else
if((cnt - k) & 1) sign = -1;
else sign = 1;
int len = -1;
bool ok = true;
for(int j = 1; j <= m; j++)
}if(!ok) continue;
for(int j = 0; j < len; j++) cc[j] = '?';
ok = true;
for(int j = 1; j <= m; j++)
}if(!ok) break;
}if(!ok) continue;
int res = 1;
for(int j = 0; j < len; j++) if(cc[j] == '?') res = res * 26 % mods;
res = 1ll * res * c[cnt][k] % mods;
ans = (ans + res * sign + mods) % mods;
}printf("%d\n", ans);
return
0;}
列舉第一段的長度和頭,然後右移過程中由於固定了長度,所以進乙個出乙個,第三維單調。於是o(
n2) 。
雖然很水,但是有時候列舉開頭結尾換成列舉長度的方法是很好的,以長度為階段使這題變得簡單。處理兩點間的位置也可以記相對距離而不是具體座標。這種方法要牢記。
ps:這題暴力好像比正解跑得快,資料真是感人。
#include
#include
#include
#include
#include
#include
#define maxn 5005
using
namespace
std;
int d, ans, len;
char s[maxn];
int main()
}printf("%d\n", ans);
return
0;}
給定一棵n個節點的樹,去掉這棵樹的一條邊需要消耗值1,為這個圖的兩個點加上一條邊也需要消耗值1。樹的節點編號從1開始。在這個問題中,你需要使用最小的消耗值(加邊和刪邊操作)將這棵樹轉化為環,不允許有重邊。
環的定義如下:
(1)該圖有n個點,n條邊。
(2)每個頂點的度數為2。
(3)任意兩點是可達的。
樹的定義如下:
(1)該圖有n個點,n-1條邊。
(2)任意兩點是可達的。
對於20%的資料,有1≤n≤10。
對於100%的資料,有1≤n≤1000000。
第一行是乙個整數n代表節點的個數。
接下來n-1行每行有兩個整數u, v(1 ≤ u, v ≤ n),表示雙向邊(u, v)
輸出把樹轉化為環的最小消耗值。
4這是一道好題,我想了好久還碼錯了。1 2
2 3
2 4
我們發現將樹變成環其實就是先拆成鏈再連起來。其中一些邊不動,另外一些變要斷掉然後再和其他邊連成鏈。那我們怎麼知道那些邊是要切斷,哪些邊要保留呢?這裡我們考慮貪心。
如果乙個節點它的兒子沒有,不考慮。有1個兒子,肯定不要斷掉下面的邊。我們先樹形dp一下求出所有節點的兒子數siz,這裡的兒子要滿足上述的情況,記為f。一開始我的錯誤就是在這裡忘了判這個,樣例居然還過了。
然後我們再dfs一遍,如果當前的節點的f<2,不用割,如果f>=2,需要割掉自成鏈的個數就是f-1,因為我們保留其中跨根的一條鏈,還要刪掉與根父親的連邊。為什麼不考慮和父親連邊呢?因為這樣不會優(貪心)。於是我們只考慮能連到這裡的兒子,然後考慮保留一條鏈,於是我們貪心地算出了最小鏈運算元,答案就是算出來的*2+1(每個操作包括斷與連,最後要連成環要+1)。
這樣我們每次連到乙個點的兒子數是固定的,然後直接計算就可以了。注意如果是根節點的話要特判。
時間複雜度o(
n)。ps:n太大爆棧,bfs保平安。
#include
#include
#include
#include
#include
#include
#define maxn 1000010
using namespace std;
int n;
int ans;
int head_p[maxn], f[maxn], fa[maxn], q[maxn], cur = -1;
struct adj edg[maxn<<1];
void insert(int a, int b)
void bfs1()
}for(int i = tail; i > 0; i--)
}void bfs2()
for(int i = head_p[now]; ~ i; i = edg[i].next)
}}int main()
bfs1();
bfs2();
printf("%d\n", ans << 1 | 1);
return
0;}
這次比賽本來以為分數可以很理想,結果t1粗心了,t3腦抽了。這主要是我在家碼完程式就去看番了,以後一定要檢查**,有空多寫對拍,手畫資料很必要(像t3)。
還有,別天真地以為smoj是無限棧的。
2021 1 17高一模擬賽題解
就根據題意慢慢模擬就行了 只用 if 就能ac的水題 不過還是有幾個坑點的 比如負號。mitruha逐漸ccf化 include using namespace std double x,v1,v2,v3,t char ch1,ch2 double level 0 int main if level...
EZ 2017 12 17初二初三第一次膜你賽
以後平時練習還是寫一寫吧。題目搞來搞去太煩了,直接pdf存起來 t1 水題 主要是資料水,正解是設乙個闕值,然而根本沒人打。暴力出奇蹟 code includeusing namespace std inline void read int x const int n 1e5 5 int sum,a...
CQ18高一暑假前挑戰賽2 標程
昨晚打校賽,5個小時打完很累了,所以搞忘出題了。對不起學弟們,不過出的題都親自寫過一遍,可以保證題目和 長度都不長,題目難度不大 a bush博弈 includeusing namespace std intmain return0 b dp求最長公共子串行,可以反推字首 includeusing ...