USACO 2011 December Contest
Silver Division
Problem 1. CowPhotography
首先我们可以发现:若在大于等于3张照片中a牛都在b牛的前面,那么在初始状态中a牛就在b牛前面。
于是我们可以记下每张照片中每头牛的位置,然后在sort中加一个神奇的cmp函数(若a牛在2张以上的照片中在b牛前,返回1,否则返回0)
代码如下:
#include
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
map
int b[20001];
inline bool cmp(int x,int y){
int s=0;
for(int i=1;i<=5;++i) s+=a[i][x] return s>2;
}
int main()
{
//freopen("photo.in","r",stdin);
//freopen("photo.out","w",stdout);
int n=read();
for(int i=1;i<=5;++i)
for(int j=1;j<=n;++j){
int x=read();
a[i][x]=j;
if(i<2) b[j]=x;
}
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;++i) printf("%d\n",b[i]);
}
一道最短路题目。唯一特殊的是,要将一条边的长度*2,使1到n的最短路尽可能长。
考虑到:改变的边肯定在一开始的最短路中,否则改了也不影响最短路长度。
首先,肯定要求出一开始1到n的最短路,不过要记录下路径。然后枚举路径上的每条边,*2,跑最短路,比大小。
代码如下:
#include
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
int e[101][101],d[101],pre[101],n,m;
bool vis[101];
inline int bestpath(int t,int w){
memset(d,63,sizeof(d));
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
d[t]=0;
while(1){
int close=-1;
for(int i=1;i<=n;++i)
if(!vis[i]&&(close==-1||d[i]
if(close==-1) break;
vis[close]=1;
for(int i=1;i<=n;++i){
int x=d[close]+e[close][i];
if(x
pre[i]=close;
}
}
}
return d[w];
}
int main()
{
n=read(),m=read();
memset(e,63,sizeof(e));
for(int i=1;i<=m;++i){
int u=read(),v=read(),w=read();
e[u][v]=w,e[v][u]=w;
}
int s1=bestpath(1,n);
vector
for(int i=n;i!=-1;i=pre[i]) v.push_back(i);
int s2=s1;
for(int i=0;i+1
e[a][b]*=2;
e[b][a]*=2;
s2=max(s2,bestpath(1,n));
e[a][b]/=2;
e[b][a]/=2;
}
printf("%d",s2-s1);
}
一道dp题。首先,将牛排序。然后,因为题中说大伞可能比小伞便宜,我们可以从第二大的伞倒推,若比它大1的伞比它便宜,就将它的价格更新为大伞的价格。最后,n^2的dp。f[i]表示最后一把伞恰好挡住第i头牛时最少的花费。转移方程:f[i]=min(f[j]+c[a[i]-a[j+1]+1])(0
代码如下:
#include
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
int a[5001],c[100001],f[5001];
int main()
{
int n=read(),m=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=m;++i) c[i]=read();
sort(a+1,a+n+1);
for(int i=m-1;i>=1;--i) c[i]=min(c[i],c[i+1]);
for(int i=1;i<=n;++i) f[i]=c[a[i]-a[1]+1];
for(int i=2;i<=n;++i)
for(int j=1;j f[i]=min(f[i],f[j]+c[a[i]-a[j+1]+1]);
cout<
GOLD Division
Problem 1. CowPhotography
和银组第一题一模一样。。。
一道最小生成树题。问你有多少棵最小生成树。
求最小生成树可用Kruskal算法。先将边按权值排序。然后枚举每条边,每次看后面相同的边,若两点不连通,就记下这条边,然后算下个数就行了。
代码如下:
#include
#define ll long long
#define mod 1000000007
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
struct node{
int u,v,w;
}e[100001];
int p[40001];
inline bool cmp(node a,node b){
return a.w
inline int find(int x){
if(x!=p[x]) p[x]=find(p[x]);
return p[x];
}
inline bool merge(int x,int y) {
int x2=find(x);
int y2=find(y);
if(x2==y2) return 0;
p[x2]=p[y2]=p[x]=p[y]=x2;
return 1;
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int n=read(),m=read();
for(int i=1;i<=m;++i){
e[i].u=read(),e[i].v=read(),e[i].w=read();
}
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;++i) p[i]=i;
ll s1=0,s2=1;
for(int i=1;i<=m;){
int j,tot=0,num=0;
set
for(j=i;j<=m&&e[i].w==e[j].w;++j){
int x=find(e[j].u),y=find(e[j].v);
if(x!=y){
if(x
++tot;
}
}
for(;i
}
s1+=num*e[i-1].w;
if(tot==3) {
if(num==1||num==2&&s.size()==3) s2=(s2*3)%mod;
if(num==2&&s.size()==2) s2=(s2*2)%mod;
}
if(tot==2&&num==1) s2=(s2*2)%mod;
}
cout<