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\) 个不同的盒子。每个球都被分配了两个盒子,应该放在其中一个盒子里。每个盒子只能装一个球。问题是把所有的球都放到盒子里有多少种解。
题解:
对问题进行一个建模。
将每个篮子看做一个点,将球看做边,那么就将问题转换成了一个这样的问题:
有一张图,将边分配给它相邻的一个节点,且每个节点只能分配一条边,问有多少种分配方案?
对于由这种方法建出来的图,每一个联通分量之间是互不影响的,我们只需要算出每一个联通分量中的答案利用乘法原理,进行求解。

考虑一个联通分量。以为它是一个联通分量,所以只会有以下几种情况。

  1. 当 E > V 时,显然是无解的。
  2. 当 E = v 时,这种情况下,联通分量的形态是基环树,每个边都只会拥有一个点,只是边的方向的问题。所以当环不是自环的时候,答案为 2,否则为 1。
  3. 当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

我太菜了。

posted @ 2021-10-27 17:02  _程门立雪  阅读(42)  评论(1编辑  收藏  举报