A.怪盜-1412
題目地址
題意簡述
一個長度爲n+m+k包含n個數字1,m個數字2和k個數字4的數組,最多可能有多少個1412子序列?
題解
由於2和4在1412中出現的次數都是1次,所以不需要考慮將連續的4或者是連續的2分開的情況
就比如
1444412
沒必要寫成
4414412
很明顯會出現4的浪費
因爲子序列的相對位置是不能改變的
那麼我們實際上需要考慮的就是1的情況,
設開頭的1有個,在4和2之間的1就會有個
最多子序列即求解
即相當於求解二次函數最大值
所以序列的組成是這樣的
x個1 k個4 n-x個1 m個2
第一個1我們可以從第一部分取C1x,x箇中取一個作爲第一個
第二個4我們從第二個部分取C1K,往後同理
於是最後的結果
ans=(n * n)/4 * k*m
代碼
int main(){
int t; RD(t);
while(t--){
LL n, m, k; RDD(n, m, k);
if (n == 1) {
printf("0\n");
}
else {
LL ans = m * ((n * n) / 4) * k;
OT(ans);
}
}
}
B. Dis2
題目地址
題意簡述
給你樹的連接,要你求解每個節點所連接的距離爲2的節點有多少個?
-
樣例輸入
4
1 2
2 3
3 4 -
樣例輸出
1
1
1
1
點{1,3}的距離爲2,點{2,4}的距離爲2。
題解
每個遍歷每個節點(1)所連接的節點(2),通過節點(2)的大小能很清楚計算出與節點(1)距離爲2的點有多少個,但要注意節點(1)連接着節點(2),同時節點(2)也連接着節點(1),所以在計算節點(2)的大小的時候需要注意減1
代碼
typedef vector<int> VI;
const int maxn = 2e6 + 50;
VI G[maxn];
int main(){
int n; RD(n);
int u, v;
REP(i, n - 1){
RD(u, v);
G[u].PB(v);
G[v].PB(u);
}
FOR_1(i, 1, n){
LL ans = 0;
for(int v: G[i]){
ans += G[v].size() - 1;
}
cout << ans << '\n';
}
}
C.序列卷積之和
題目地址
題意簡述
求解 mod
題解
預處理前綴和統計前綴和出現的數量。
n = 2
a[1] * a[1] + a[1] * a[1] + a[1] * a[2] + a[2] * a[2] + a[2] * a[2]
n = 3
a[1] * a[1] + a[1] * a[1] + a[1] * a[2] + a[2] * a[2] + a[1] * a[1] + a[1] * a[2] + a[1] * a[3] + a[2] * a[2] + a[2] * a[3] + a[3] * a[3] + a[2] * a[2] + a[2] * a[2] + a[2] * a[3] + a[3] * a[3] + a[3] * a[3]
//附打印程序
int main(){
int n; cin >> n;
for(int l = 1; l <= n; l++) {
for(int r = l; r <= n; r++) {
for(int i = l; i <= r; i++) {
for(int j = i; j <= r; j++){
cout << "a" << "[" << i << "]" << " * " << "a" << "[" << j << "]" << " + ";
}
}
}
}
}
可以很清楚的看到n = 2和 n = 3有那麼一些相似之處
n = 2有的n = 3都有
在n=2中出現都是兩次
類推,
易知只與存在關係,同理只與存在關係,所以可以分開考慮
再看一眼n=2的時候的情況
a[1] * a[1] + a[1] * a[1] + a[1] * a[2] + a[2] * a[2] + a[2] * a[2]
其實可以化簡成
以此去想
外層還有兩個循環,類似推斷
這裏是引用
來源於官方題解 https://ac.nowcoder.com/discuss/430962
代碼
const int maxn = 2e5+60;
LL a[maxn], s[maxn], s2[maxn],ans = 0;
const int mod = 1e9 + 7;
int main(){
int n; RD(n);
FOR_1(i, 1, n) cin >> a[i];
FOR_1(i, 1, n) s[i] = (s[i - 1] + a[i]) % mod;
FOR_1(i, 1, n) s2[i] = (s2[i - 1] + s[i]) % mod;
FOR_1(i, 1, n)
{
ans += i * a[i] % mod * ((s2[n] - s2[i-1] + mod) % mod - (n - i + 1) * s[i-1] % mod + mod) % mod;
ans %= mod;
}
cout << ans << endl;
}
D.寶石裝箱
題目地址
題意簡述
顆寶石裝進個箱子使得每個箱子中都有一顆寶石。第顆寶石不能裝入第個箱子。求合法的裝箱方案對取模。
(兩種裝箱方案不同當且僅當兩種方案中存在一顆編號相同的寶石裝在不同編號的箱子中。)
- 輸入樣例
2
1 2 - 輸出樣例
1
題解
容斥+dp
- 在不考慮不符合情況時,總的方案數allnum
- 合法方案數實際上就是等於總的方案數 減去 不合法方案數
- 設函數表示x箱子中不合法的方案數
- 設表示前個箱子中,存在j個不合法的方案數
- 這裏運用dp,要注意,你所計算的是方案數,而不是揹包問題中的重量或者是權重什麼的
在前i個箱子中有j個不合法方案數,可能是由於前i-1個箱子中就有j個不合法方案數,也有可能是第i個箱子纔有j個不合法方案數,所以是
至少i個箱子裝了不合法的寶石的方案數
根據容斥,可得
代碼
const int maxn = 1e4+50;
LL dp[maxn], fact[maxn];
LL a[maxn];
const LL mod = 998244353;
void init(){
memset(a, 0, sizeof a);
fact[0] = 1;
FOR_1(i, 1, maxn - 1){
fact[i] = fact[i - 1] * i % mod;
}
}
int main(){
init();
int n; cin >> n;
FOR_1(i, 1, n){
LL x; RDD(x); a[x]++;;
}
dp[0] = 1;
FOR_1(i, 1, n){
for(int j = i; j >= 1; j--){
(dp[j] += dp[j - 1] * a[i]) %= mod;
}
}
LL ans = 0;
dp[0] = 1;
FOR_1( i, 0, n){
if (i & 1) ans -= dp[i] * fact[n - i];
else ans += dp[i] * fact[n - i];
ans = (ans + mod) % mod;
}
ans %= mod;
cout << ans << '\n';
}
case通過率爲%13.3可以考慮一下是不是爆int的問題