USACO Section 4
前言
好久没更新这个系列了,最近闲的无聊写一下。有两题搜索懒得写了。
P2737 [USACO4.1]麦香牛块Beef McNuggets
https://www.luogu.com.cn/problem/P2737
解题思路
先只考虑\(a_1\),假设我们拼出了\(w\),那么一定能拼出\(w+ka_1\),换句话我们考虑最大的不能拼出的\(ka_1+w(0<w<a_1)\)。
考虑到\(gcd\neq 1\)显然无解所以\(a\)中肯定存在\(gcd(a_i,a_1)=1\),这样对于每个\(ka_i\% a_1(k<a_1)\)都会有不同的值,所以根据鸽笼原理最大不能拼出的\(ka_1+w\leq a_1a_i-a_i\),这个范围不会很大,暴力背包就好了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=256*256;
int n,a[11],f[L];
int main()
{
	scanf("%d",&n);
	int d=0,flag=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		d=__gcd(d,a[i]);
		flag|=(a[i]==1);
	}
	if(d!=1||flag)return puts("0")&0;
	f[0]=1;
	for(int i=1;i<L;i++)
		for(int j=1;j<=n;j++)
			if(i>=a[j])f[i]|=f[i-a[j]];
	for(int i=L-1;i>=1;i--)
		if(!f[i])return printf("%d\n",i)&0;
	return 0;
}
P2738 [USACO4.1]篱笆回路Fence Loops
https://www.luogu.com.cn/problem/P2738
解题思路
每个篱笆开两个点,每个篱笆对之间记录他们用来连接的端点然后建图就变成最小环问题了。
枚举篱笆断边然后两端跑最短路就好了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=210;
struct node{
	int to,next,w;
	bool ban;
}a[N*N];
int n,tot,ls[N],f[N],p[N][N],rev[N],pos[N],ans;
bool v[N];queue<int> q;
void addl(int x,int y,int w){
	a[++tot].to=y;
	a[tot].next=ls[x];
	ls[x]=tot;a[tot].w=w;
	return;
}
void SPFA(int s){
	memset(f,0x3f,sizeof(f));
	q.push(s);v[s]=1;f[s]=0;
	while(!q.empty()){
		int x=q.front();q.pop();v[x]=0;
		for(int i=ls[x];i;i=a[i].next){
			int y=a[i].to;
			if(a[i].ban)continue;
			if(f[x]+a[i].w<f[y]){
				f[y]=f[x]+a[i].w;
				if(!v[y])q.push(y);
			}
		}
	}
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x,l,s1,s2;
		scanf("%d%d%d%d",&pos[i],&l,&s1,&s2);
		rev[pos[i]]=i;
		addl(i*2-1,i*2,l);addl(i*2,i*2-1,l);
		for(int j=0;j<s1;j++)
			scanf("%d",&x),p[i][x]=i*2-1;
		for(int j=0;j<s2;j++)
			scanf("%d",&x),p[i][x]=i*2;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(p[i][j])addl(p[i][j],p[rev[j]][pos[i]],0);
	ans=2147483647;
	for(int i=1;i<=n;i++){
		int w=i*2;
		a[w].ban=a[w-1].ban=1;
		SPFA(w-1);ans=min(ans,a[w].w+f[w]);
		a[w].ban=a[w-1].ban=0;
	}
	printf("%d\n",ans);
	return 0;
}
P2740 [USACO4.2]草地排水Drainage Ditches
https://www.luogu.com.cn/problem/P2740
解题思路
最大流模板
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=210;
struct node{
	int to,next,w;
}a[N<<1];
int n,m,tot=1,ls[N],dep[N],ans;
queue<int> q;
void addl(int x,int y,int w){
	a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
	a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
}
bool bfs(){
	memset(dep,0,sizeof(dep));dep[1]=1;
	while(!q.empty())q.pop();q.push(1);
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=ls[x];i;i=a[i].next){
			int y=a[i].to;
			if(!a[i].w||dep[y])continue;
			dep[y]=dep[x]+1;
			if(y==m)return 1;
			q.push(y);
		}
	}
	return 0;
}
int dinic(int x,int flow){
	if(x==m)return flow;
	int rest=0,k;
	for(int i=ls[x];i;i=a[i].next){
		int y=a[i].to;
		if(dep[x]+1!=dep[y]||!a[i].w)continue;
		rest+=(k=dinic(y,min(flow-rest,a[i].w)));
		a[i].w-=k;a[i^1].w+=k;
		if(flow==rest)return flow;
	}
	if(!rest)dep[x]=0;
	return rest;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		int x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		addl(x,y,w);
	}
	while(bfs())
		ans+=dinic(1,2147483647);
	printf("%d\n",ans);
	return 0;
}
P1894 [USACO4.2]完美的牛栏The Perfect Stall
https://www.luogu.com.cn/problem/P1894
解题思路
最大匹配,把上面那个最大流改一下就好了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=410;
struct node{
	int to,next,w;
}a[N*N];
int n,m,s,t,tot=1,ls[N],dep[N],ans;
queue<int> q;
void addl(int x,int y,int w){
	a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
	a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
}
bool bfs(){
	memset(dep,0,sizeof(dep));dep[s]=1;
	while(!q.empty())q.pop();q.push(s);
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=ls[x];i;i=a[i].next){
			int y=a[i].to;
			if(!a[i].w||dep[y])continue;
			dep[y]=dep[x]+1;
			if(y==t)return 1;
			q.push(y);
		}
	}
	return 0;
}
int dinic(int x,int flow){
	if(x==t)return flow;
	int rest=0,k;
	for(int i=ls[x];i;i=a[i].next){
		int y=a[i].to;
		if(dep[x]+1!=dep[y]||!a[i].w)continue;
		rest+=(k=dinic(y,min(flow-rest,a[i].w)));
		a[i].w-=k;a[i^1].w+=k;
		if(flow==rest)return flow;
	}
	if(!rest)dep[x]=0;
	return rest;
}
int main()
{
	scanf("%d%d",&n,&m);s=n+m+1;t=s+1;
	for(int i=1;i<=n;i++){
		int k,x;scanf("%d",&k);
		for(int j=0;j<k;j++)
			scanf("%d",&x),addl(i,x+n,1);
	}
	for(int i=1;i<=n;i++)addl(s,i,1);
	for(int i=1;i<=m;i++)addl(i+n,t,1);
	while(bfs())
		ans+=dinic(s,2147483647);
	printf("%d\n",ans);
	return 0;
}
P2751 [USACO4.2]工序安排Job Processing
https://www.luogu.com.cn/problem/P2751
解题思路
考虑贪心,第一个正着做,开一个单调队列然后每次取最早做完的。
第二个和第一个一样反着做,然后两道工序时间长的配时间短的就好了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=1100;
int n,A,B,t[N],s[N],a[N],ans;
priority_queue<pair<int,int> > q;
int main()
{
	scanf("%d%d%d",&n,&A,&B);
	for(int i=1;i<=A;i++)scanf("%d",&a[i]),q.push(mp(-a[i],i));
	for(int i=1;i<=n;i++){
		pair<int,int> k=q.top();
		t[i]=-k.first;q.pop();
		q.push(mp(k.first-a[k.second],k.second));
	}
	printf("%d ",t[n]);
	while(!q.empty())q.pop();
	for(int i=1;i<=B;i++)scanf("%d",&a[i]),q.push(mp(-a[i],i));
	for(int i=1;i<=n;i++){
		pair<int,int> k=q.top();
		s[i]=-k.first;q.pop();
		q.push(mp(k.first-a[k.second],k.second));
	}
	for(int i=1;i<=n;i++)
		ans=max(ans,s[i]+t[n-i+1]);
	printf("%d\n",ans);
	return 0;
}
P2687 [USACO4.3]逢低吸纳Buy Low, Buy Lower
https://www.luogu.com.cn/problem/P2687
解题思路
最长下降子序列,但是因为是股价序列不同,所以方案数转移的时候枚举到上一个与它相等的就要停止。
要开\(long\ double\)或者高精度
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define ll long double
using namespace std;
const int N=5100;
long long n,a[N];
ll f[N],g[N];
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	a[++n]=0;a[0]=1e18;f[0]=g[0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<i;j++)
			if(a[j]>a[i])f[i]=max(f[i],f[j]+1);
		for(int j=i-1;j>=0;j--)
			if(a[j]==a[i])break;
			else if(a[j]>a[i]&&f[j]+1==f[i])
				g[i]+=g[j];
	}
	printf("%.0Lf %.0Lf\n",f[n]-2,g[n]);
	return 0;
}
P2752 [USACO4.3]街道赛跑Street Race
https://www.luogu.com.cn/problem/P2752
解题思路
先跑一遍\(Flody\),然后枚举点,每次重新跑\(Flody\)判必经点。
然后如果是必经点用第一次的\(Flody\)判中间点。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=51;
int n;bool a[N][N],f[N][N],g[N][N];
vector<int>ans1,ans2;
int main()
{
	while(1){
		int x;scanf("%d",&x);
		if(x==-1)break;
		while(x!=-2){
			a[n][x]=g[n][x]=1;
			scanf("%d",&x);
		}
		n++;
	}
	for(int i=0;i<n;i++)a[i][i]=g[i][i]=1;
	for(int k=0;k<n;k++)
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				g[i][j]|=g[i][k]&g[k][j];
	for(int p=1;p<n-1;p++){
		memset(f,0,sizeof(f));
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				if(i!=p&&j!=p)f[i][j]=a[i][j];
		for(int k=0;k<n;k++)
			for(int i=0;i<n;i++)
				for(int j=0;j<n;j++)
					f[i][j]|=f[i][k]&f[k][j];
		if(!f[0][n-1]){
			ans1.push_back(p);
			bool flag=1;
			for(int i=0;i<n;i++){
				if(i==p)continue;
				if(f[0][i])flag&=(g[i][p]&&!g[p][i]);
				if(f[i][n-1])flag&=g[p][i];
			}
			if(flag)ans2.push_back(p);
		}
	}
	printf("%d",ans1.size());for(int i=0;i<ans1.size();i++)printf(" %d",ans1[i]);putchar('\n');
	printf("%d",ans2.size());for(int i=0;i<ans2.size();i++)printf(" %d",ans2[i]);putchar('\n');
	return 0;
}
P2753 [USACO4.3]字母游戏Letter Game
解题思路
先看懂题,然后发现虽然字符串很多,但是合法的字符串个数不会超过\(2^7\)所以只跑合法的不会超过\(O(n^2)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int w[26]={2,5,4,4,1,6,5,5,1,7,6,3,5,2,3,5,7,2,1,2,4,6,6,7,5,7};
struct node{
	char s[7];
	int l,c;
}a[410000];
int n,ans,c[30],v[30];
char t[7];
vector<pair<int,int> >pr;
//bool operator==(node x,node y){
//	for(int i=0;i<7;i++)
//		if(x.s[i]!=y.s[i])return 0;
//	return 1;
//}
//bool operator<(node x,node y){
//	for(int i=0;i<7;i++)
//		if(x.s[i]!=y.s[i])return x.s[i]<y.s[i];
//	return 0;
//}
bool check(node x,node y){
	for(int i=0;i<26;i++)v[i]=c[i];
	for(int i=0;i<x.l;i++)
		if(v[x.s[i]-'a'])v[x.s[i]-'a']--;
		else return 0;
	for(int i=0;i<y.l;i++)
		if(v[y.s[i]-'a'])v[y.s[i]-'a']--;
		else return 0;
	return 1;
}
int main()
{
	scanf("%s",t);int m=strlen(t);
	for(int i=0;i<m;i++)c[t[i]-'a']++;
	while(1){
		++n;scanf("%s",a[n].s);
		if(a[n].s[0]=='.'){n--;break;}
		a[n].l=strlen(a[n].s);
		if(!check(a[n],a[0]))
		{n--;continue;}
		for(int i=0;i<a[n].l;i++)
			a[n].c+=w[a[n].s[i]-'a'];
	}
	ans=0;
	for(int i=1;i<=n;i++){
		if(a[i].c>ans)ans=a[i].c,pr.clear();
		if(a[i].c==ans)pr.push_back(make_pair(i,0));
		for(int j=i;j<=n;j++){
			if(check(a[i],a[j])){
				if(a[i].c+a[j].c>ans)ans=a[i].c+a[j].c,pr.clear();
				if(a[i].c+a[j].c==ans)pr.push_back(make_pair(i,j));
			}
		}
	}
	printf("%d\n",ans);
	for(int i=0;i<pr.size();i++)
		printf("%s %s\n",a[pr[i].first].s,a[pr[i].second].s);
	return 0;
}
P1344 [USACO4.4]追查坏牛奶Pollutant Control
https://www.luogu.com.cn/problem/P1344
解题思路
以前写的了,费用流模板,那个费用变成第一关键值乘上一个很大的值加上第二个关键值就好了。
code
// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const ll N=320,M=10010,inf=1e18,cs=2333;
struct node{
	ll to,next,w;
}a[M*2];
ll tot=1,n,s,t,m,ans;
ll dep[N],ls[N];
queue<int> q;
void addl(ll x,ll y,ll w)
{
	a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
	a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
}
bool bfs()
{
	memset(dep,0,sizeof(dep));
	while(!q.empty()) q.pop();
	q.push(s);dep[s]=1;
	while(!q.empty())
	{
		ll x=q.front();q.pop();
		for(ll i=ls[x];i;i=a[i].next)
		{
			ll y=a[i].to;
			if(!dep[y]&&a[i].w){
				dep[y]=dep[x]+1;
				if(y==t) return true;
				q.push(y);
			}
		}
	}
	return false;
}
ll dinic(ll x,ll flow)
{
	ll rest=0,k;
	if(x==t) return flow;
	for(ll i=ls[x];i;i=a[i].next)
	{
		ll y=a[i].to;
		if(dep[x]+1==dep[y]&&a[i].w)
		{
			rest+=(k=dinic(y,min(a[i].w,flow-rest)));
			a[i].w-=k;a[i^1].w+=k;
			if(rest==flow) return flow;
		}
	}
	if(!rest) dep[x]=0;
	return rest;
}
void netflow()
{
	while(bfs())
	  ans+=dinic(s,inf);
}
int main()
{
	scanf("%lld%lld",&n,&m);
	s=1;t=n;
	for(ll i=1;i<=m;i++)
	{
		ll x,y,w;
		scanf("%lld%lld%lld",&x,&y,&w);
		w=w*cs+1;addl(x,y,w);
	}
	netflow();
	printf("%lld %lld",ans/cs,ans%cs);
}
后面两道搜索懒得写了
USACO Section 4的更多相关文章
- 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&& ... 
- USACO Section 3.3: Riding the Fences
		典型的找欧拉路径的题.先贴下USACO上找欧拉路径的法子: Pick a starting node and recurse on that node. At each step: If the no ... 
- USACO Section 3.3 Camlot(BFS)
		BFS.先算出棋盘上每个点到各个点knight需要的步数:然后枚举所有点,其中再枚举king是自己到的还是knight带它去的(假如是knight带它的,枚举king周围的2格(网上都这么说,似乎是个 ... 
- [IOI1996] USACO Section 5.3 Network of Schools(强连通分量)
		nocow上的题解很好. http://www.nocow.cn/index.php/USACO/schlnet 如何求强连通分量呢?对于此题,可以直接先用floyd,然后再判断. --------- ... 
- USACO Section 5.3 Big Barn(dp)
		USACO前面好像有类似的题目..dp(i,j)=min(dp(i+1,j),dp(i+1,j+1),dp(i,j+1))+1 (坐标(i,j)处无tree;有tree自然dp(i,j)=0) .d ... 
- USACO Section 1.3 Prime Cryptarithm 解题报告
		题目 题目描述 牛式的定义,我们首先需要看下面这个算式结构: * * * x * * ------- * * * <-- partial product 1 * * * <-- parti ... 
- USACO Section 1.1 Your Ride Is Here 解题报告
		题目 问题描述 将字符串转变为数字,字母A对应的值为1,依次对应,字母Z对应的值为26.现在有一个字符串,将其中的每个字符转变为数字之后进行累乘,最终的结果对47求余数. 题目给你两个字符串,其中的字 ... 
- USACO Section 1.1-1 Your Ride Is Here
		USACO 1.1-1 Your Ride Is Here 你的飞碟在这儿 众所周知,在每一个彗星后都有一只UFO.这些UFO时常来收集地球上的忠诚支持者.不幸的是,他们的飞碟每次出行都只能带上一组支 ... 
- USACO section 1.1 C++题解
		USACO section1.1:DONE 2017.03.03 TEXT Submitting Solutions DONE 2017.03.04 PROB Your Ride Is Here [A ... 
- USACO Section 1.1PROB Your Ride Is Here
		题目传送门 不能提交哦 http://www.nocow.cn/index.php/Translate:USACO/ride /* ID: jusonal1 PROG: ride LANG: C+ ... 
随机推荐
- 剑指 Offer 13. 机器人的运动范围
			剑指 Offer 13. 机器人的运动范围 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] .一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左.右.上.下移动一 ... 
- java关键字native、static、final详解
			native: native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中.Java语言本身不能对操作系统底层进行访问和操作,但是可 ... 
- python创建字典多种方式
			1.创建空字典 >>> dic = {} >>> type(dic) <type 'dict'> 2.直接赋值创建 >>> dic = ... 
- SpringCloud降级熔断 Hystrix
			1.分布式核心知识之熔断.降级讲解 简介:系统负载过高,突发流量或者网络等各种异常情况介绍,常用的解决方案 1.熔断: 保险丝,熔断服务,为了防止整个系统故障,包含子和下游服务 下单服 ... 
- Map 综述(一):彻头彻尾理解 HashMap
			转载自:https://blog.csdn.net/justloveyou_/article/details/62893086 摘要: HashMap是Map族中最为常用的一种,也是 Java Col ... 
- String与Int类型的转换
			http://blog.sina.com.cn/s/blog_4f9d6b1001000bfo.html int -> String int i=12345; String s="&q ... 
- Go进阶--httptest
			目录 基本使用 扩展使用 接口context使用 模拟调用 测试覆盖率 参考 单元测试的原则,就是你所测试的函数方法,不要受到所依赖环境的影响,比如网络访问等,因为有时候我们运行单元测试的时候,并没有 ... 
- 在ES5中模拟类
			1.Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__. var _this = Object.create(fn.prototype);这句代码的 ... 
- 阿里云服务器部署mongodb
			在阿里云上买了个服务器,部署mongodb遇到一些坑,解决办法也是从网上搜集而来,把零零碎碎的整理记录一下. 服务器是:Alibaba Cloud Linux 下载安装 mongodb官网下载实在是太 ... 
- Qt中的Q_PROPERTY宏浅析
			1. Q_PROPERTY Qt提供了一个绝妙的属性系统,Q_PROPERTY()是一个宏,用来在一个类中声明一个属性property,由于该宏是qt特有的,需要用moc进行编译,故必须继承于QObj ... 
