模擬15 題解(waiting)

2022-03-16 14:57:20 字數 3329 閱讀 5959

定義f[i][j]表示列舉到i位置,已經使用過了j個隊,

$f[i][j]+=f[i-1][t] ( t \in [max(0,j-k),j])$滾動一下

這是個o(n^3)的,考慮如何優化,發現可以使用字首和,避免列舉t,$o(n^2)$

1 #include2 #include3 #include4 #include5 #include6

#define r register

7#define ll long long

8using

namespace

std;

9 inline int

read()

1013

while(ch<='

9'&&ch>='0')

14return f*x;15}

16const

int mod=998244353;17

const

int maxn=10000005;18

intn,m,k;

19 ll f[2][maxn],g[2

][maxn];

20int

main()

2132

for(int j=k+1;j<=m;j++)

33 g[1][j]=g[1][j-1]%mod;

34 r int cnt=1;35

for(r int i=2;i<=n;++i)

3648

}49 printf("

%lld\n

",f[cnt][m]%mod);

50 }

view code

問題轉化成:m個物品,放到n個抽屜裡,每個至少放乙個,最多放k個

若任何的限制: c(m+n-1,n-1)表示一共有m個物品,分成n組就要用n-1個擋板,把擋板也看成空位,總共m+n-1個空位,選出來n-1個

若考慮至少放乙個:c(m-n+n-1,n-1)先用n個物品給每個抽屜放乙個,剩了m-n個物品,再加上n-1個空,剩下的同上

再考慮k的限制:c(n,i)*c(m-n-i*k+n-1,n-1)表示至少有i個的數量已經超過k(>=k+1)所以先給n個抽屜放乙個之後,再給n個放上k個,使之成為k+1個

就是m-n-i*k,再加上n-1個空

陣列開2e7就行,顯然n>m直接return0

1 #include2 #include3 #include4 #include5 #include6

#define r register

7#define ll long long

8using

namespace

std;

9inline ll read()

1013

while(ch<='

9'&&ch>='0')

14return f*x;15}

16const ll mod=998244353;17

const ll maxn=20000005;18

ll fac[maxn],inv[maxn],facinv[maxn];

19ll n,m,k;

20void

init()

2130}31

ll c(ll n,ll m)

3236

intmain()

3740

init();

41 ll ans=c(m-1,n-1)%mod;

42for(ll i=1;i<=n;i++)

4348 printf("

%lld\n

",ans%mod);

49 }

view code

對於無環的情況,最優解就是,圖中的最長鏈的長度,,,為什麼?

注意審題:只是炸城市,道路不炸,故某一城市毀了,其他城市的聯通性不變,所以最長鏈上最少要炸的次數就是鏈長,而其他的路徑,當然可以在炸最長鏈上的每個節點的同時也一起炸,有環的話,tarjan所點成scc,然後拓撲排序,把入度為0的節點放入佇列中,列舉其子節點,子節點的答案為,父節點答案加上子節點的scc大小,並且這個點可能使用多次,所以要每次取最大值

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8

using

namespace

std;

9 inline int

read()

1013

while(ch<='

9'&&ch>='0')

14return f*x;15}

16const

int maxn=1000005;17

intn,m;

18struct

nodee[2*maxn];int

h[maxn],nu;

21void add(int x,int

y)22

27struct

nodcec[maxn*2];int

hc[maxn],nuc;

30void add_c(int x,int

y)31

36int

dfn[maxn],low[maxn],num,top,cnt;

37int

sta[maxn],ins[maxn],bl[maxn];

38 vectorscc[maxn];

39void tarjan(int

x)40

52else

if(ins[y])

53 low[x]=min(low[x],dfn[y]);54}

55if(dfn[x]==low[x])while(y!=x);61}

62}63int

ind[maxn],ans[maxn];

64void

topo()

6580}81

}82intmain()

8391

//cout<

92for(int i=1;i<=n;i++)

93if(!dfn[i])

94tarjan(i);

95for(int x=1;x<=n;x++)

96103

}104

topo();

105int an=0

;106

for(int i=1;i<=n;i++)

107 an=max(ans[i],an);

108 printf("

%d\n

",an);

109 }

view code

模擬17 題解

t1 a.入陣曲 60 演算法 維護一下某一列的從第一行到這一行和二維字首和 然後列舉上下左右邊界,o n 4 100 演算法 省掉左右邊界的列舉,改為從左向右掃一邊,記錄總和 k的餘數,並放入桶中,可以發現,如果這個值出現過,那說明這個位置的總和減去那個位置的差 即這個區間 是k的正倍數 t2又是...

模擬16 題解

貪心,對於每只青蛙,跳的時候盡量遠,越遠選擇越多 注意若用set實現,要先insert 0 1 include2 include3 include4 include5 include6 include 7 define r register 8using namespace std 9 inline...

模擬113 題解

手玩發現這個東西好像有一點規律。考慮在最優的方案下,每增加乙個點對答案的貢獻 0 1 然後隨便寫寫就好了。把 x 向 x 能偷的節點建邊。發現這個東西一定會形成森林,其中一些樹為基環樹,其餘為普通形態的樹。對於普通形態的樹,顯然可以賺到其中所有能賺的錢。但基環樹對應著不能從環上乙個節點偷另乙個節點。...