ECNA 2014 部分题解 | 训练记录0703

29 篇文章 0 订阅
6 篇文章 0 订阅

D. Generalized Roman Numerals [思维dp]

在这里插入图片描述
dp

#pragma GCC optimize(2)
#pragma GCC optimize(3)
unordered_set<int> save[maxn][maxn];
int mp[1000];
int num[10000007];
void QuickSort(int l,int r) {
	if(l>=r) return;
	int left=l,right=r;//
	ll temp=num[(left+right)/2];//设左边的为基值
	int mid=(left+right)/2;
	while(left<right) { //相等的 return;就可以了
		while(num[left]<temp) left++;
		while(num[right]>temp) right--;
		if(left<=right) {
			ll stemp=num[left];
			num[left]=num[right];
			num[right]=stemp;
			left++;
			right--;
		}
	}
	QuickSort(l,right);
	QuickSort(left,r);
}
int main() {
	mp['I'] = 1;
	mp['V'] = 5;
	mp['X'] = 10;
	mp['L'] = 50;
	mp['C'] = 100;
	char s[55];
	int kase = 0;
	while(scanf("%s",s) != EOF) {
		if(s[0] == '0') break;
		int len = strlen(s);
		for(int i=0; i<=len; i++) {
			for(int j=0; j<=len; j++) {
				save[i][j].clear();
			}
		}
		for(int i=0; i<len; i++) {
			save[i][i].insert(mp[s[i]]);//自己到自己只能是当前字符
		}
		// meiju 长度
		for(register int i=2; i<=len; i++) {
			for(register int j=0; j+i<=len; j++) {
				int st = j;
				int ed = j+i-1;
				//ed - st + 1 => length=i
				for(register int md=j; md<ed; ++md) {
					for(auto A : save[st][md]) {
						for(auto B : save[md+1][ed]) {
							if(A >= B) save[st][ed].insert(A + B);
							else save[st][ed].insert(- A + B);
						}
					}
				}
			}
		}
		vector<int> v;
		int idx = 0;
		for(int x:save[0][len-1]) v.push_back(x);
//		for(int x:save[0][len-1]) {
//			num[++idx] = x;
//		}
		sort(v.begin(), v.end());
//		sort(num+1,num+1+idx);
//		QuickSort(1, idx);
//		v.erase(unique(v.begin(), v.end()),v.end());
		printf("Case %d: ",++kase);
//		for(int x: v) printf("%d ", x);
		for(int i=0; i<v.size(); i++) {
			printf("%d%c",v[i],i == v.size()-1?'\n':' ');
		}
//		puts("");
//		for(int i=1; i<=idx; i++) {
//			printf("%d%c",num[i],i == idx?'\n':' ');
//		}
	}
	return 0;
}

E. Inspectors [拆点跑最小费用最大流]

在这里插入图片描述

/*** keep hungry and calm PushyTao!***/

typedef pair<ll, ll> PLL;
struct Edge {
	int u, v, cap, flow, cost;
	Edge(int _u, int _v, int _cap, int _flow, int _cost) {
		u = _u, v = _v, cap = _cap, flow = _flow, cost = _cost;
	}
};
struct MinCostMaxFlow {
	int n, m;
	vector<Edge> edges;
	vector<int> G[maxn];
	int vis[maxn], dis[maxn], p[maxn], a[maxn];
	void init(int x) {
		this->n = x;
		for (int i = 0; i <= x; i++) G[i].clear();
		edges.clear();
	}
	void add(int u, int v, int cap, int cost) {
		edges.push_back(Edge(u, v, cap, 0, cost));
		edges.push_back(Edge(v, u, 0, 0, -cost));
		m = edges.size();
		G[u].push_back(m - 2);
		G[v].push_back(m - 1);
	}
	bool BellmanFord(int s, int t, ll &flow, ll &cost) {
		for (int i = 0; i <= n; i++) dis[i] = 0x3f3f3f3f;
		memset(vis, 0, sizeof vis);
		queue<int> que;
		que.push(s);
		dis[s] = 0, vis[s] = 0, p[s] = 0, a[s] = 0x3f3f3f3f;
		while (que.size()) {
			int u = que.front();
			que.pop();
			vis[u] = 0; /// not in the queue
			for (int i = 0; i < G[u].size(); i++) {
				int id = G[u][i];
				Edge e = edges[id];
				int to = e.v;
				if (e.cap > e.flow && dis[to] > dis[u] + e.cost) {
					dis[to] = dis[u] + e.cost;
					p[to]   = id;
					a[to]   = min(a[u], e.cap - e.flow);
					if (!vis[to]) {
						que.push(to);
						vis[to] = 1;
					}
				}
			}
		}
		if (dis[t] >= 0x3f3f3f3f) return false;
		flow += a[t];
		cost += 1LL * dis[t] * 1LL * a[t];
		for (int u = t; u != s; u = edges[p[u]].u) {
			edges[p[u]].flow += a[t];
			edges[p[u] ^ 1].flow -= a[t];
		}
		return true;
	}
	PLL MinCostAndMaxFlow(int s, int t) {
		ll flow = 0;
		ll cost = 0;
		while (BellmanFord(s, t, flow, cost));
		return {flow, cost};
	}
} solve;
int n, m, s, t;
int main() {
	/**
	cin >> n >> m >> s >> t;
	solve.init(n);
	for (int i = 1; i <= m; i++) {
	    int u = read, v = read, flow = read, cost = read;
	    solve.add(u, v, flow, cost);
	}
	PLL ans = solve.MinCostAndMaxFlow(s, t);
	cout << ans.first << ' ' << ans.second << endl;
	**/
	int _ = read;
	for(int kase=1; kase<=_; kase++) {
		n = read;
		solve.init(1003);
		for(int i=1; i<=n; i++) {
			solve.add(0,i,1,0);// s <-> i_in 
			solve.add(i+n,1001,1,0);// i_out <-> t
			for(int j=i+1; j<=n; j++) {
				int value = read;
				solve.add(i,j+n,1,value);// in_i <-> j_out
				solve.add(j,i+n,1,value);// in_j <-> i_out
			}
		}
		PLL p = solve.MinCostAndMaxFlow(0,1001);
//		cout << p.first << endl;
		printf("Case %d: %d\n",kase, p.second);
	}
	return 0;
}
/**
2
4
10 20 10
10 20
10
4
15 20 10
10 20
15

->
Case 1: 40
Case 2: 40
**/

H. Time Warp [模拟]

在这里插入图片描述
可以参考

/*** keep hungry and calm PushyTao!***/
void print(int kase, ll seco) {
	int h,m,s;
	h = m = s = 0;
	seco = (seco + 12 * 60 * 60) % (12 * 60 * 60);//;//
	h = seco / 3600 + 1;
	m = seco % 3600 / 60;
	s = seco % 60;
	printf("Case %d: %d:%02d:%02d\n",kase, h,m,s);
}
void solve(int a,int b,string c,int kase) {
	if(c[0] == 'a') {
		int cur = 30 * (12 - b);
		int need = 0;
		if(a > cur) need = a - cur;
		else need = 360 - cur + a;
		int t = round(need / (11.0 / 120.0));
		print(kase, 3600 * (b - 1) + t);
	} else if(c[0] == 't') {
		int cur = 30 * (12 - b);
		int need = 0;
		if(a < cur) need = -(a - cur);
		else need = 360 + cur - a;
		int t = round(need / (11.0 / 120.0));
		print(kase, 3600 * (b - 1) - t);
	}
}
int main() {
	int _ = read;
	int kase;
	for(kase = 1; kase <= _; kase++) {
		string c;
		int a = read;
		cin >> c;
		int b = read;
		solve(a,b,c,kase);
	}
	return 0;
}
/**


**/

A. Cure for the Common Code [KMP]

在这里插入图片描述

#include <bits/stdc++.h>

typedef long long ll;

template<typename T>
std::istream& operator>> (std::istream& in, std::vector<T>& vt)
{
	for (auto& i : vt) in >> i;
	return in;
}
template<typename T>
std::ostream& operator<< (std::ostream& out, const std::vector<T>& vt)
{
	for (auto& i : vt) out << i << " ";
	out << std::endl;
	return out;
}
void printAll() {  }
template<typename T1, typename... T2>
void printAll(const T1& first, const T2&... second)
{
	std::cout << first;
	if (sizeof...(second)) {
		std::cout << ", ";
	}
	printAll(second...);
}
template<typename T1, typename... T2>
void print(const T1& first, const T2&... second)
{
	std::cout << "[";
	printAll(first, second...);
	std::cout << "]" << std::endl;
}

#define N (int)(5e2 + 10)

struct Kmp {
	static int nxt[N];
	// nxt[i]
	// 表示前i个字母,下标应该转移到nex[i]
	// 本质含义是最长前后缀,但是由于字符串从0开始计数的,所以正好指向的是最长前后缀的前缀的下一个位置,即需要匹配的位置

private:
	static void init() {
		memset(nxt, 0, sizeof(nxt));
	}
public:
	static int get(const std::string& s1, bool init = false)
	{
		const int& n = s1.size();

		for (int i = 1, j = 0; i < n; i++) {
			while (j && s1[i] != s1[j]) j = nxt[j - 1];
			if (s1[i] == s1[j]) j++;
			nxt[i] = j;
		}
		int len = n - nxt[n - 1];
		return len;
	}
};

#define print(...) 

int Kmp::nxt[]{};

int getBitCnt(int n) {
	int res = 0;
	while (n) {
		res += 1;
		n /= 10;
	}
	return res;
}

int main()
{
	print(getBitCnt(9));

	int T = 1;
	std::string str;
	while (std::cin >> str) {
		if (str == "0") break;

		const int& n = str.size();
		std::vector<std::vector<int>> f(n, std::vector<int>(n, 1e9));

		for (int i = 0; i < n; i++) {
			f[i][i] = 1;
		}

		for (int len = 2; len <= n; len++) {
			for (int l = 0, r = len - 1; r < n; l++, r++) {
				for (int k = l; k < r; k++) {
					f[l][r] = std::min(f[l][r], f[l][k] + f[k + 1][r]);
				}

				int cnt = r - l + 1;
				int len = Kmp::get(str.substr(l, cnt), true);
				if (l == 1 && r == 3) {
					print(len);
				}
				if (cnt % len == 0) {
					int tmp = 0;
					if (len >= 2) tmp += 2;
					tmp += f[l][l + len - 1];
					tmp += getBitCnt(cnt / len);
					f[l][r] = std::min(f[l][r], tmp);
				}
			}
		}

		print(str.substr(0, 10));
		printf("Case %d: %d\n", T++, f[0][n - 1]);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值