USACO Section 4

1|0前言

好久没更新这个系列了,最近闲的无聊写一下。有两题搜索懒得写了。


2|0P2737 [USACO4.1]麦香牛块Beef McNuggets

https://www.luogu.com.cn/problem/P2737

2|1解题思路

先只考虑a1,假设我们拼出了w,那么一定能拼出w+ka1,换句话我们考虑最大的不能拼出的ka1+w(0<w<a1)

考虑到gcd1显然无解所以a中肯定存在gcd(ai,a1)=1,这样对于每个kai%a1(k<a1)都会有不同的值,所以根据鸽笼原理最大不能拼出的ka1+wa1aiai,这个范围不会很大,暴力背包就好了。

2|2code

#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; }

3|0P2738 [USACO4.1]篱笆回路Fence Loops

https://www.luogu.com.cn/problem/P2738

3|1解题思路

每个篱笆开两个点,每个篱笆对之间记录他们用来连接的端点然后建图就变成最小环问题了。

枚举篱笆断边然后两端跑最短路就好了。

3|2code

#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; }

4|0P2740 [USACO4.2]草地排水Drainage Ditches

https://www.luogu.com.cn/problem/P2740

4|1解题思路

最大流模板

4|2code

#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; }

5|0P1894 [USACO4.2]完美的牛栏The Perfect Stall

https://www.luogu.com.cn/problem/P1894

5|1解题思路

最大匹配,把上面那个最大流改一下就好了。

5|2code

#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; }

6|0P2751 [USACO4.2]工序安排Job Processing

https://www.luogu.com.cn/problem/P2751

6|1解题思路

考虑贪心,第一个正着做,开一个单调队列然后每次取最早做完的。

第二个和第一个一样反着做,然后两道工序时间长的配时间短的就好了。

6|2code

#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; }

7|0P2687 [USACO4.3]逢低吸纳Buy Low, Buy Lower

https://www.luogu.com.cn/problem/P2687

7|1解题思路

最长下降子序列,但是因为是股价序列不同,所以方案数转移的时候枚举到上一个与它相等的就要停止。

要开long double或者高精度

7|2code

#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; }

8|0P2752 [USACO4.3]街道赛跑Street Race

https://www.luogu.com.cn/problem/P2752

8|1解题思路

先跑一遍Flody,然后枚举点,每次重新跑Flody判必经点。

然后如果是必经点用第一次的Flody判中间点。

8|2code

#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; }

9|0P2753 [USACO4.3]字母游戏Letter Game

9|1解题思路

先看懂题,然后发现虽然字符串很多,但是合法的字符串个数不会超过27所以只跑合法的不会超过O(n2)

9|2code

#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; }

10|0P1344 [USACO4.4]追查坏牛奶Pollutant Control

https://www.luogu.com.cn/problem/P1344

10|1解题思路

以前写的了,费用流模板,那个费用变成第一关键值乘上一个很大的值加上第二个关键值就好了。

10|2code

// 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); }

后面两道搜索懒得写了


__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15183449.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(39)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示