1. 程式人生 > 其它 >10.27 校內模擬賽題解報告

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

我太懶了。