UOJ 214 合唱隊形

2021-08-11 06:17:07 字數 3193 閱讀 1235

有n個人每個人有乙個字符集初始為空。

有tot個事件,每個事件形如在第ai個人的字符集裡放了bi這個小寫字母。

每個時刻等概率發生乙個事件。

有乙個長度為m的字串s。某個時刻如果存在編號連續的m個人,按從小到大的順序發現對於第i個人字符集裡都有si,那麼則勝利。

問勝利的期望時間,要求判斷無解,答案在模意義下進行。設f

(i) 表示時刻i還沒有勝利的概率。

答案是∑

i>=0f

(i)

考慮容斥,列舉哪些位置作為起點在時刻t匹配成功。 f(

t)=∑

2n−m

+1−1

i=0g

(h(i

),t)

∗(−1

)bit

coun

t(i)

h(i)表示i這個二進位制狀態內的起點匹配所需要發生的事件總數。

g(i,t)表示長度為t的序列,每個位置是1~tot的數,有i個數一定要出現,概率是多少。

g的計算當然可以容斥 g(

i,t)

=∑ij

=0cj

i∗(t

ot−j

tot)

t∗(−

1)j

發現f的求和最終變成這個地方對(t

ot−j

tot)

t 的求和。

如果是真分數求和當然很好做。

注意j可以為0,那麼會出現1t

求和,怎麼辦?

只考慮1

t 最終的係數那麼是∑n

−m+1

i=0c

in−m

+1∗(

−1)i

容易發現因為

n>=

m 這個式子的值是0。

如果沒有發現這個,我們還可以換容斥方法。 f(

t)=∑

2n−m

+1−1

i=1g

(h(i

),t)

∗(−1

)bit

coun

t(i)

+1g(i,t)的意義改為,長度為t的序列,每個位置是1~tot的數,有i個數一定不要全部出現,概率是多少。 此時g

(i,t

)=∑i

j=1c

ji∗(

tot−

jtot

)t∗(

−1)j

+1可以發現現在就不帶1t

的項了。

新的式子可以考慮每種情況被計算的次數證明正確性。

回到原來的地方。

然後注意∑t

>=0x

t=11

−x,這個可能涉及求逆元,請進行預處理避免複雜度多帶乙個log。

這個做法的時間複雜度是o(

2n−m

tot)

,只有m較大才能用。

對於m較小的情況,不妨設dp[i,s,k]表示確定到第i個位置,(i-m,i)裡成為起點的二進位制狀態為s,帶權方案數是多少(因為注意最後有-1的係數)。那麼也很好做了,複雜度是o(

2mnt

ot) ,當然因為我好像毛都沒預處理所以我的程式是o(

2mnm

tot)

#include

#include

#include

#define fo(i,a,b) for(i=a;i<=b;i++)

#define fd(i,a,b) for(i=a;i>=b;i--)

#define two(i) (1<<(i))

using

namespace

std;

typedef

long

long ll;

const

int maxn=30+2,mo=998244353;

char s[maxn],h[maxn];

bool dis[maxn][maxn];

int b[maxn][maxn],d[maxn],cnt[maxn*maxn],niy[maxn*maxn];

int c[maxn*maxn][maxn*maxn],f[2][two(15)][maxn*26];

int i,j,k,l,r,t,n,m,now,tot,ni,ans,ca;

bool czy;

int qsm(int x,int y)

bool pd()

return0;}

int calc(int x)

int g(int cnt)

return t;

}void dfs(int x,int f,int y)

dfs(x+1,f,y);

int i,t=0;

bool czy=1;

fo(i,x,x+m-1)

if (!dis[i][s[i-x+1]-'a'])

else

if (czy)

}void brute()

void solve()

d[s[t]-'a']++;

if (d[s[t]-'a']==1) r++;

}l/=2;

}if (!czy) continue;

(f[1-now][j/2][k+r]+=f[now][j][k])%=mo;

if (i+m-1

<=n&&dis[i][s[1]-'a'])

}now=1-now;

}fo(k,0,tot) cnt[k]=0;

fo(j,0,two(m-1)-1)

fo(k,0,tot) (cnt[k]+=f[now][j][k])%=mo;

ans=0;

fo(k,0,tot) (ans+=(ll)cnt[k]*g(k)%mo)%=mo;

(ans+=mo)%=mo;

printf("%d\n",ans);

}int main()

scanf("%s",s+1);

if (!pd())

ni=qsm(tot,mo-2);

fo(i,1,tot) niy[i]=qsm(1-(ll)(tot-i)*ni%mo,mo-2);

c[0][0]=1;

fo(i,1,tot)

if (n-m+1

<=16) brute();

else solve();

}}

合唱隊形 DP

合唱隊形 chorus.pas c cpp n位同學站成一排,老師要請其中的 n k 位同學出列,使得剩下的k位同學排成合唱隊形。合唱隊形是指這樣的一種隊形 設k位同學從左到右依次編號為1,2 k,他們的身高分別為t1,t2,tk,則他們的身高滿足t1 ti 1 tk 1 i k 你的任務是,已知所...

合唱隊形 dp

題目描述 n位同學站成一排,老師要請其中的 n k 位同學出列,使得剩下的k位同學不交換位置就能排成合唱隊形。合唱隊形是指這樣的一種隊形 設k位同學從左到右依次編號為1,2,k,他們的身高分別為t1,t2,tk,則他們的身高滿足t1 t2 ti ti ti 1 tk 1 i k 你的任務是,已知所有...

合唱隊形 NOIP

合唱隊形 noip time limit 1000ms memory limit 65536k description n位同學站成一排,老師要請其中的 n k 位同學出列,使得剩下的k位同學排成合唱隊形。合唱隊形是指這樣的一種隊形 設k位同學從左到右依次編號為1,2 k,他們的身高分別為t1,t2...