USACO Section 1.3 题解 (洛谷OJ P1209 P1444 P3650 P2693)
usaco ch1.4
sort(d , d + c, [](int a, int b) -> bool { return a > b; });
生成与过滤 generator&&filter
dfs:简化多重循环,枚举点对与判环
洛谷OJ
P1209 [USACO1.3]修理牛棚 Barn Repair
P1444 [USACO1.3]虫洞wormhole
P3650 [USACO1.3]滑雪课程设计Ski Course Design
P2693 [USACO1.3]号码锁 Combination Lock
Barn Repair
题意
数轴上有给你c个点,问用m个线段覆盖这些点的最小总长度。
题解
贪心
原题等价于在一条线段上有c个点,让你切出m-1条线段(不包含任何一个点),使得切的线段长度和最大。
所以直接处理出任意相邻两点的距离,取前m-1大的即可
代码
/*
ID: suuttt2
TASK:  barn1
LANG: C++
*/
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <set>
#include<algorithm>
#include<map>
typedef long long ll;
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define md(x) x=(x+mod)%mod
int smain();
#define ONLINE_JUDGE
int main() {
	//ios::sync_with_stdio(false);
#ifdef ONLINE_JUDGE
	FILE *myfile;
	myfile = freopen("barn1.in", "r", stdin);
	if (myfile == NULL)
		fprintf(stdout, "error on input freopen\n");
	FILE *outfile;
	outfile = freopen("barn1.out", "w", stdout);
	if (outfile == NULL)
		fprintf(stdout, "error on output freopen\n");
#endif
	smain();
	return 0;
}
const int maxn = 2e2 + 5;
//#define x first
//#define y second
#define FAST_IO ios_base::sync_with_stdio(false); cin.tie(nullptr)
int n, m, k;
int st[maxn];
int del[maxn];
int smain() {
	FAST_IO;
	int m, s, c;
	cin >> m >> s >> c;
	rep(i, 1, c) {
		cin >> st[i];
	}
	sort(st + 1, st + 1 + c);
	rep(i, 2, c) {
		del[i] = st[i] - st[i - 1];
	}
	sort(del + 2, del + 1 + c, [](int a, int b) -> bool { return a > b; });
	int ans = 0;
	rep(i, 2, 2 + m - 2)ans += del[i] - 1;
	ans = st[c] - st[1] + 1 - ans;
	if (m >=c)ans = c;
	cout << ans << endl;
	cin >> n;
	//cin >> N;
	return 0;
}
/*
*/
Combination Lock
题意
你有一个海关锁(行李箱上的那种),有三个数字,每个数字可以转到1~n。
有两个正确密码。
现在锁破了,如果某位和正确密码对应的一位绝对值差小于2,那么就被认为是正确密码,求有几个密码可以开锁?
题解
我的实现是生成。
dfs 生成正确答案,存在set里面。
标程暴力枚举,然后筛出正解。
是for三层,过滤出正确答案。
另外关于数字环:
我用了mod来模拟转数字,而标程用了其他的方法,避免了1,2 的特判。
代码
//头文件省略
int n, m, k;
int a[4], b[4];
set<int> ans;
void fix(int &x) {
	if (x < 0)x += n;
	if (x == 0)x = n;
    if(x>n){
            if(n==1)x=n;
            else if(n==2)x=(x%2?2:1);
                 else x=x%n;
    }
}
int harsh(int a[]) {
	return (a[1]*(n + 1) +a[2])*(n + 1) +a[3];
}
void  dfs(int n,int a[]) {
	if (n == 4) { ans.insert(harsh(a)); return; }
	rep(i, -2, 2) {
		int tmp = a[n];
		a[n] += i;
		fix(a[n]);
		dfs(n + 1,a);
		a[n] = tmp;
	}
}
int smain() {
	FAST_IO;
	cin >> n;
	int mod = n;
	rep(i, 1, 3)cin >> a[i];
	rep(i, 1, 3)cin >> b[i];
	dfs(1, a);
	dfs(1, b);
	cout << ans.size() << endl;
	cin >> n;
	return 0;
}
//标程代码
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int N;
bool close(int a, int b)
{
  if (abs(a-b) <= 2) return true;
  if (abs(a-b) >= N-2) return true;
  return false;
}
bool close_enough(int n1, int n2, int n3,
		  int c1, int c2, int c3)
{
  return close(n1,c1) && close(n2,c2) && close(n3,c3);
}
int main(void)
{
  int f1, f2, f3;
  int m1, m2, m3;
  ifstream fin("combo.in");
  fin >> N;
  fin >> f1 >> f2 >> f3;
  fin >> m1 >> m2 >> m3;
  fin.close();
  int total = 0;
  for (int n1=1; n1<=N; n1++)
    for (int n2=1; n2<=N; n2++)
      for (int n3=1; n3<=N; n3++)
	if (close_enough(n1,n2,n3,f1,f2,f3) ||
	    close_enough(n1,n2,n3,m1,m2,m3))
	  total++;
  ofstream fout("combo.out");
  fout << total << "\n";
  fout.close();
  return 0;
}
Wormholes
题意
给你二维坐标系上12个点,两两分组,组内的点会互相传送。有一头牛在平面上沿x正方向移动。如果走到某个点,就必须被传送到另一个。
问有几种分组方法,使得牛会进入死循环?
sample input
4
0 0
0 1
1 0
1 1
sample output
2
hint
(1,2)(3,4):1->2->1...
(1,4)(3,2):1->2->3->4->1...
题解
枚举再筛选。
先枚举所有点对组合,然后判环。
具体实现可以用建图,也可以用两个数组指针。
枚举点对的方法,就是dfs。
判环的方法,可以dfs中记录层数,如果跑了足够多步(实测21),就有环。也可以在把0设置在最右边,跑足够多此,看有没有跑到0点。
代码
int n, ans;
pii p[maxn];
vector<int> E[maxn];
vector<int> EE[maxn*13+14];
set<int> c;
int s[13];
vector<int> v;
set<int> tmps;
map<int, int> jump;
void test(int n) {
	cout << n << endl;
	for (auto t : v)cout << t << ' '; cout << endl;
	cout << endl;
}
bool iscyc(int N, int cnt) {
	if (cnt > 21)return 1;
	if (jump[N])N = jump[N]; cnt++;
	for (auto t : E[N]) {
		if (iscyc(t, cnt + 1))return 1;
	}
	return 0;
}
bool hascyc() {
	rep(i,1,n) {
		if (iscyc(i,1)) {
			return 1;
		}
	}
	return 0;
}
int minele(int s[]) {
	rep(i, 1, n)if (s[i])return i;
	return 1;
}
void all(int N) {
	if (N == 2) {
		rep(i,1,n)if(s[i])v.push_back(i);
		//用map缩点
		rep(i, 1, n)if (i % 2) {
			jump[v[i]] = v[i - 1];
			jump[v[i - 1]] = v[i];
		}
		if (hascyc()) ans++;
		jump.clear();
		rep(i, 1, 2)v.pop_back();
		return;
	}
	int mn = minele(s);
	s[mn] = 0;
	v.push_back(mn);
	rep(i,1,n) if (s[i]) {
		v.push_back(i);
		s[i] = 0;
		all(N - 2);
		v.pop_back();
		s[i] = 1;
	}
	s[mn] = 1;
	v.pop_back();
}
int smain() {
	FAST_IO;
	cin >> n;
	rep(i, 1, n)cin >> p[i].x >> p[i].y;
	sort(p + 1, p + 1 + n, [](pii a, pii b)->bool {return a.y == b.y ? a.x < b.x : a.y < b.y; });
	rep(i, 1, n-1) {
			if(p[i].y == p[i+1].y)E[i].pb(i+1);
	}
	rep(i, 1, n)s[i]=1;
	all(n);
	cout << ans << endl;
	cin >> n;
	return 0;
}
//标程
//用的数组指针判环,数组枚举数对
#include <iostream>
#include <fstream>
using namespace std;
#define MAX_N 12
int N, X[MAX_N+1], Y[MAX_N+1];
int partner[MAX_N+1];
int next_on_right[MAX_N+1];
bool cycle_exists(void)
{
  for (int start=1; start<=N; start++) {
    // does there exist a cylce starting from start
    int pos = start;
    for (int count=0; count<N; count++)
      pos = next_on_right[partner[pos]];
    if (pos != 0) return true;
  }
  return false;
}
// count all solutions
int solve(void)
{
  // find first unpaired wormhole
  int i, total=0;
  for (i=1; i<=N; i++)
    if (partner[i] == 0) break;
  // everyone paired?
  if (i > N) {
    if (cycle_exists()) return 1;
    else return 0;
  }
  // try pairing i with all possible other wormholes j
  for (int j=i+1; j<=N; j++)
    if (partner[j] == 0) {
      // try pairing i & j, let recursion continue to
      // generate the rest of the solution
      partner[i] = j;
      partner[j] = i;
      total += solve();
      partner[i] = partner[j] = 0;
    }
  return total;
}
int main(void)
{
  ifstream fin("wormhole.in");
  fin >> N;
  for (int i=1; i<=N; i++) fin >> X[i] >> Y[i];
  fin.close();
  for (int i=1; i<=N; i++) // set next_on_right[i]...
    for (int j=1; j<=N; j++)
      if (X[j] > X[i] && Y[i] == Y[j]) // j right of i...
	if (next_on_right[i] == 0 ||
	    X[j]-X[i] < X[next_on_right[i]]-X[i])
	  next_on_right[i] = j;
  ofstream fout("wormhole.out");
  fout << solve() << "\n";
  fout.close();
  return 0;
}
心路历程:
这个section留到最后的一道题。
想着这个专题的题都是很骚的循环枚举,
那这题肯定也是,其实不是啊QAQ。
所以昨天就一直想不用dfs的方法。
今天开始写dfs枚举点对和判环。
说实话以前都没写过orz。
枚举点对本来打算用set优化一下数组,最后发现set不能在for(auto t:set)里面插入删除,结果还是用了个cnt数组。
然后写判环,先要建图,发现这个图还要删边(现在想想暴力加边就够了QAQ),于是想建两个图,写到一半突然根据图的形态想到可以缩点(我用了hash)。写完了以后wa了一组数据,debug半天,发现缩点是错的QAQ,因为到某点时必须要转移到另一个点。于是想了一下,把两个点用map互相联系一下(其实用个数组也行),每次搜到某点时 v=map[v]一下。
dfs的话一开始想用map判环,最后都要写宽搜了。然后想到其实只要记录走的步数大于12个的话就有环了,但不知道为什么,至少要走21步才行QAQ
结论:图论不要瞎搞,全想清楚了再实现
#include<algorithm>
#include<iostream>
#include<sstream>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<math.h>
#include<stdio.h>
#include<vector>
#include<queue>
#include<string>
#include<ctime>
#include<stack>
#include<map>
#include<set>
#include<list>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define REP(i,j,k) for(int i = (int)j;i < (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define MD(x) x%=mod
#define FAST_IO ios_base::sync_with_stdio(false); cin.tie(nullptr)
#define pii pair<int,int>
#define x first
#define y second
typedef double db;
typedef long long ll;
const int MAXN = 1e6;;
const int maxn = 10 + 5;
const int INF = 1e9;
const db eps = 1e-7;
const int mod = 1e9 + 7;
int n, ans;
pii p[maxn];
vector<int> E[maxn];
vector<int> EE[maxn*13+14];
set<int> c;
int s[13];
vector<int> v;
set<int> tmps;
void test(int n) {
	cout << n << endl;
	for (auto t : v)cout << t << ' '; cout << endl;
	cout << endl;
}
bool iscyc(int N, int cnt) {
	if (cnt > 12)return 1;
	for (auto t : EE[N]) {
		if (iscyc(t, cnt + 1))return 1;
	}
	return 0;
}
bool hascyc() {
	for(auto t:tmps) {
		if (iscyc(t,1)) {
			return 1;
		}
	}
	return 0;
}
int minele(int s[]) {
	rep(i, 1, n)if (s[i])return i;
	return 1;
}
void all(int N) {
	if (N == 2) {
		rep(i,1,n)if(s[i])v.push_back(i);
		//
		//缩点对判环前先判掉两点环
		int ok = 0;
		rep(i, 0, n-1) if(i%2){
			tmps.insert(v[i-1] * 13 + v[i]);
		}
		rep(i,1,n)
			rep(j, 0, E[i].size()-1) {
			if (tmps.count(i * 13 + E[i][j])|| tmps.count(i + E[i][j] * 13)) {
				ok = 1;
			}
		}
		if (ok == 1)ans++,test(1);
		else {//建缩点后的图,判环
			rep(i, 1, n)
				rep(j, 0, E[i].size() - 1) {
				int V = E[i][j];
				int xx=0, yy=0;
				for (auto t : tmps)if (t % 13 == i || t / 13 == i)xx = t;
				for (auto t : tmps)if (t % 13 == V || t / 13 == V)yy = t;
				EE[xx].push_back(yy);
				int lala = 1;
			}
			if (hascyc())ans++,test(2); 
		}
		for(auto t:tmps)EE[t].clear();
		tmps.clear();
		rep(i, 1, 2)v.pop_back();
		return;
	}
	int mn = minele(s);
	s[mn] = 0;
	v.push_back(mn);
	rep(i,1,n) if (s[i]) {
		v.push_back(i);
		s[i] = 0;
		all(N - 2);
		v.pop_back();
		s[i] = 1;
	}
	s[mn] = 1;
	v.pop_back();
}
int main() {
	FAST_IO;
	cin >> n;
	rep(i, 1, n)cin >> p[i].x >> p[i].y;
	sort(p + 1, p + 1 + n, [](pii a, pii b)->bool {return a.y == b.y ? a.x < b.x : a.y < b.y; });
	rep(i, 1, n-1) {
			if(p[i].y == p[i+1].y)E[i].pb(i+1);
	}
	rep(i, 1, n)s[i]=1;
	all(n);
	cout << ans << endl;
	cin >> n;
}
/*
6
1 1
2 1
3 1
4 1
5 1
2 2
*/
Ski Course Design
题意
有1000座山,每座山的高度为0~100,现在要使任意两座山的高度差小于等于17。你可以改变一座山的长度,cost=deltaH^2。求最小花费。
题解
注意到,我们只要知道最低的那座山的高度,即可O(n)得到最终花费。所以枚举最低高度即可,复杂度为O(n*100).
相对的如果你要枚举每座山的高度,那么将是指数级别的。
代码
/*
ID: suuttt2
TASK:  skidesign
LANG: C++
*/
#include <iostream>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
int smain();
//#define ONLINE_JUDGE
int main() {
	//ios::sync_with_stdio(false);
#ifdef ONLINE_JUDGE
	FILE *myfile;
	myfile = freopen("skidesign.in", "r", stdin);
	if (myfile == NULL)
		fprintf(stdout, "error on input freopen\n");
	FILE *outfile;
	outfile = freopen("skidesign.out", "w", stdout);
	if (outfile == NULL)
		fprintf(stdout, "error on output freopen\n");
#endif
	smain();
	return 0;
}
const int maxn = 1000 + 5;
int n;
int h[maxn];
int smain() {
	cin >> n;
	rep(i, 1, n) {
		cin >> h[i];
	}
	sort(h + 1, h + 1 + n);
	int ans = 100 * 100 * 1000+1;
	rep(mn, 0, 100-17) {
		int tmp = 0;
		rep(i, 1, n) {
			if(h[i]<mn)
				tmp += (h[i] - mn)*(h[i] - mn);
			if (h[i] > mn + 17)
				tmp += (h[i] - mn - 17)*(h[i] - mn - 17);
		}
		ans = min(ans, tmp);
	}
	cout << ans << endl;;
	//cin >> n;
	return 0;
}
心路历程
发现了洛谷有usaco专题,但是不能交#define ONLINE_JUDGE封装orz
USACO Section 1.3 题解 (洛谷OJ P1209 P1444 P3650 P2693)的更多相关文章
- 题解——洛谷P2734 游戏A Game 题解(区间DP)
		题面 题目背景 有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,游戏由玩家1开始,两人轮流从序列的任意一端取一个数,取数后该数字被去掉并累加到本玩家的 ... 
- 题解 洛谷P5018【对称二叉树】(noip2018T4)
		\(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ... 
- 题解 洛谷 P3396 【哈希冲突】(根号分治)
		根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ... 
- 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)
		题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ... 
- 题解-洛谷P4229 某位歌姬的故事
		题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ... 
- 题解-洛谷P4724 【模板】三维凸包
		洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ... 
- 题解-洛谷P4859 已经没有什么好害怕的了
		洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ... 
- 题解-洛谷P5217 贫穷
		洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ... 
- [洛谷OJ] P1114 “非常男女”计划
		洛谷1114 “非常男女”计划 本题地址:http://www.luogu.org/problem/show?pid=1114 题目描述 近来,初一年的XXX小朋友致力于研究班上同学的配对问题(别想太 ... 
随机推荐
- Centos7 安装 scrapy
			Centos7 安装 scrapy ( *:此python版本为 2.7 ) 1.先安装 python (2.7) 在安装 scrapy 要先安装 python 和 pip, 链接:https:// ... 
- Junit的基础学习
			一个强大的单元测试框架: 一.组成部分: 1.注解: (1)@Test 注解: 放在测试方法上,表示这是用于测试其他方法的一个测试单元 @Test public void testSum1(){ Sy ... 
- Docker:  repository, image, container
			1. 查看image: docker images 2. 查看信息: docker info 3. 搜索image: docker search [image_name], 比如: docker se ... 
- Vue相关目录
			cli入门-项目搭建 组件 Router路由 生命周期 数据监听 cli搭建web服务介绍 vuex和axios介绍 
- POJ1321  棋盘问题(简单搜索)
			题意: 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放 ... 
- js在数组arr中随机获取count数量的元素
			// 在数组arr中随机获取count数量的元素; const getRandomArrayElements = (arr, num) => { // 新建一个数组,将传入的数组复制过来,用于运 ... 
- Vulnerability Scanning
			1.Vulnerability scanning with Nmap Scripting Engine the Nmap Script Engine provide a alrge number of ... 
- hdu5592 倒序求排列+权值线段树
			这种题为什么要用到主席树啊..8说了,直接上代码 /* 1-n的排列,给定所有前缀的逆序对数量,要求恢复排列 首先能确定最后一个数是什么,然后倒序确定即可 开线段树找空位:如果Ai-Ai-1=k,说明 ... 
- vs调试的时候,指定的参数已超出有效值的范围。参数名:sit ,先仔细看看错误和我的一样不一样
			https://www.cnblogs.com/pei123/p/7694947.html 指定的参数已超出有效值的范围.参数名:sit ,先仔细看看错误和我的一样不一样 更新了1709就这样了,的确 ... 
- vuejs使用jsx语法
			想要vuejs项目支持jsx语法,需要一些插件 babel-plugin-transform-vue-jsx Babel plugin for Vue 2.0 JSX 使用方法: 安装 npm ins ... 
