定義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 #include6view code#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 }
問題轉化成: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 #include6view code#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 }
對於無環的情況,最優解就是,圖中的最長鏈的長度,,,為什麼?
注意審題:只是炸城市,道路不炸,故某一城市毀了,其他城市的聯通性不變,所以最長鏈上最少要炸的次數就是鏈長,而其他的路徑,當然可以在炸最長鏈上的每個節點的同時也一起炸,有環的話,tarjan所點成scc,然後拓撲排序,把入度為0的節點放入佇列中,列舉其子節點,子節點的答案為,父節點答案加上子節點的scc大小,並且這個點可能使用多次,所以要每次取最大值
1 #include2 #include3 #include4 #include5 #include6 #include7 #include8view codeusing
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 }
模擬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 能偷的節點建邊。發現這個東西一定會形成森林,其中一些樹為基環樹,其餘為普通形態的樹。對於普通形態的樹,顯然可以賺到其中所有能賺的錢。但基環樹對應著不能從環上乙個節點偷另乙個節點。...