10.27 校內模擬賽題解報告
阿新 • • 發佈:2021-10-27
T1
題意:
現在有連續 \(n\) 天,老闆娘需要分配她的工作時間。
在第 \(i\) 天工作每小時需要消耗 \(a_i\) 的精力,老闆娘希望合理分配自己的工
作時間使自己消耗盡量少的精力。
但老闆又不希望老闆娘摸魚,所以他要求老闆娘對於任意的連續7天她工作的總時間都不能少於7小時。
因為工作的特殊性,老闆娘只能在每天分配整數小時的工作時間(當然能為0)。
題解:
DP 題。
\(f_i\) 表示在第 \(i\) 天上班則前 \(i\) 天要花費的最少精力。
先假設只需要工作一個小時,
\(f_i = \min(f_i, f_j + a[i])\)。
而題目中要求要工作 7 個小時,就是將工作一個小時得到的最優解乘以7。
\(f_i = \min(f_i, f_j + a[i] \times 7)\)
關於最後的答案。
因為連續七天,工作 7 小時,所以只需要取最後7天中答案的最小值。
/* Date: Source: Knowledge: */ #include <iostream> #include <cstdio> #include <cstring> #define orz cout << "AK IOI" << "\n" #define int long long using namespace std; const int maxn = 10010; int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();} return x * f; } void print(int X) { if(X < 0) X = ~(X - 1), putchar('-'); if(X > 9) print(X / 10); putchar(X % 10 ^ '0'); } int Max(int a, int b){ return a > b ? a : b; } int Min(int a, int b){ return a < b ? a : b; } int T, n, a[maxn], f[maxn]; signed main() { //freopen("job.in", "r", stdin); //freopen("job.out", "w", stdout); T = read(); while(T--) { n = read(); for(int i = 1; i <= n; i++) a[i] = read(); for(int i = 1; i <= n; i++) f[i] = 1e18; int ans = 1e18; for(int i = 1; i <= n; i++) { for(int j = Max(0, i - 7); j < i; j++) f[i] = Min(f[i], f[j] + a[i] * 7); } for(int i = Max(1, n - 6); i <= n; i++) ans = Min(ans, f[i]); printf("%lld\n", ans); } //fclose(stdin); //fclose(stdout); return 0; } /* 2 10 1 6 3 2 4 5 2 1 2 7 10 1 1 1 1 1 1 1 1 1 1 */
我還是感覺這個 DP 好假啊!!
T2
題意:
你有 \(n\) 個不同的球和 \(m\) 個不同的盒子。每個球都被分配了兩個盒子,應該放在其中一個盒子裡。每個盒子只能裝一個球。問題是把所有的球都放到盒子裡有多少種解。
題解:
對問題進行一個建模。
將每個籃子看做一個點,將球看做邊,那麼就將問題轉換成了一個這樣的問題:
有一張圖,將邊分配給它相鄰的一個節點,且每個節點只能分配一條邊,問有多少種分配方案?
對於由這種方法建出來的圖,每一個聯通分量之間是互不影響的,我們只需要算出每一個聯通分量中的答案利用乘法原理,進行求解。
考慮一個聯通分量。以為它是一個聯通分量,所以只會有以下幾種情況。
- 當 E > V 時,顯然是無解的。
- 當 E = v 時,這種情況下,聯通分量的形態是基環樹,每個邊都只會擁有一個點,只是邊的方向的問題。所以當環不是自環的時候,答案為 2,否則為 1。
- 當V = E - 1時,這種情況下聯通分量是一棵樹。每一個點都可能會沒有邊。所以這種情況下的方案數為 V。
/*
Date:
Source:
Knowledge:
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define orz cout << "AK IOI" << "\n"
#define int long long
using namespace std;
const int mod = 998244353;
const int maxn = 3e5 + 10;
int read()
{
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
void print(int X)
{
if(X < 0) X = ~(X - 1), putchar('-');
if(X > 9) print(X / 10);
putchar(X % 10 ^ '0');
}
int Max(int a, int b){
return a > b ? a : b;
}
int Min(int a, int b){
return a < b ? a : b;
}
int T, n, m, ans, dfn[maxn], ed, nod;
struct node{
int u, v, nxt;
}e[maxn << 1];
int js, head[maxn];
void add(int u, int v)
{
e[++js] = (node){u, v, head[u]};
head[u] = js;
}
void init()
{
js = 0, ans = 1;
memset(dfn, 0, sizeof dfn);
memset(head, 0, sizeof head);
}
queue<int> q;
int bfs(int s)
{
int sum = 0, flag = 0, nod = 0;
q.push(s);
dfn[s] = 1;
while(!q.empty())
{
int u = q.front(); q.pop();
nod++;
for(int i = head[u]; i; i = e[i].nxt)
{
sum++;
int v = e[i].v;
if(v == u) flag = 1; //自環
if(dfn[v]) continue;
dfn[v] = 1;
q.push(v);
}
}
sum /= 2;
if(sum == nod - 1) return nod;
if(sum == nod) return 2 - flag;
return 0;
}
signed main()
{
//freopen("ball.in", "r", stdin);
//freopen("ball.out", "w", stdout);
T = read();
while(T--)
{
init();
n = read(), m = read();
for(int i = 1; i <= n; i++)
{
int u = read(), v = read();
add(u, v), add(v, u);
}
for(int i = 1; i <= m; i++)
{
if(dfn[i]) continue;
ans = ans * bfs(i) % mod;
}
printf("%lld\n", ans % mod);
}
fclose(stdin);
fclose(stdout);
return 0;
}
T3
我太懶了。