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
我太菜了。