高二 高一 初三模擬賽25 總結

2021-08-09 11:47:36 字數 4569 閱讀 7545

這次比賽比較簡單,然而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

a? ?b

樣例2

1 1

?????

樣例1:

樣例2:

881343

(注:881343 = 26^5 mod 1000003。)

這題可以用很暴力的狀壓dp切掉,但是優美的方法是容斥原理。

就是那個被大佬們成為廣義容斥原理的東東。

首先注意題目求的是恰好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 ...