2017.10.10队内互测——高校模拟赛
出题人:Dewct,zzk,Cunese,whales
Problem 1 :
题目来源:http://poj.org/problem?id=2709
首先确定只对于彩色颜料需要的套装数,再用多余的颜料尝试配置灰色颜料,若无法配置需要的毫升数则再购置一套颜料,为使最大化利用剩余颜料,则由大到小选三种颜料依次-1配置,并在每次配置后排序。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define RI register int
using namespace std;
int n,maxn,ans,sum,cnt,tot;
int num[100010],chi[100010];
bool flag;
int read()
{
char ch=getchar();
int ret=0;
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9')
{
ret=ret*10+(ch-'0');
ch=getchar();
}
return ret;
}
bool cmp(int a,int b)
{
return a>b;
}
void solve(int k)
{
tot=0;
for(RI i=1;i<=n;i++)
chi[i]=k*50-num[i];
sort(chi+1,chi+n+1,cmp);
cnt=1;
while(tot<num[n+1])
{
if(chi[cnt+2]==0)
{
k++;
for(int i=1;i<=n;i++)
chi[i]+=50;
}
else
{
tot++;
chi[cnt]--;
chi[cnt+1]--;
chi[cnt+2]--;
sort(chi+1,chi+n+1,cmp);
}
}
ans=k;
}
int main()
{
while(scanf("%d",&n)&&n)
{
maxn=-1e9+7;
for(RI i=1;i<=n+1;i++)
{
num[i]=read();
if(num[i]>maxn&&i<=n)
maxn=num[i];
}
if(maxn%50==0)
ans=maxn/50;
else ans=maxn/50+1;
solve(ans);
printf("%d\n",ans);
}
return 0;
}
Problem 2 :
题目来源:http://hzwer.com/4598.html
先由每个敌人向各点BFS,求出每个点到最近的敌人的距离,BFS使得每当第一次找的一点时,此时的距离即为到最近敌人的距离。
然后二分移动过程中到敌人的最小距离,BFS检验即可,注意二分写法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define RI register int
using namespace std;
int n,x,y,xs,xz,ys,yz,ans1,ans2,a,b,l,r;
int dis[1010][1010],dx[]={0,1,-1,0,0},dy[]={0,0,0,1,-1};
bool vis[1010][1010];
struct point
{
int a,b,d;
}ls[100010];
queue<point>q;
void init()
{
while(!q.empty())
{
point k=q.front();
q.pop();
for(int i=1;i<=4;i++)
{
int h=k.a+dx[i];int s=k.b+dy[i];
if(h>=x||h<0||s>=y||s<0||dis[h][s]!=-1)
continue;
dis[h][s]=dis[k.a][k.b]+1;
q.push((point){h,s,0});
}
}
}
int check(int val)
{
while(!q.empty())
q.pop();
memset(vis,0,sizeof(vis));
if(xs==xz&&ys==yz)
return 0;
vis[xs][ys]=1;
q.push((point){xs,ys,0});
while(!q.empty())
{
point k=q.front();
q.pop();
for(int i=1;i<=4;i++)
{
int h=k.a+dx[i],s=k.b+dy[i];
if(h>=x||h<0||s>=y||s<0||vis[h][s]||dis[h][s]<val)
continue;
vis[h][s]=1;
if(h==xz&&s==yz)
return k.d+1;
q.push((point){h,s,k.d+1});
}
}
return -1;
}
int main()
{
memset(dis,-1,sizeof(dis));
scanf("%d%d%d",&n,&x,&y);
scanf("%d%d%d%d",&xs,&ys,&xz,&yz);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&ls[i].a,&ls[i].b);
dis[ls[i].a][ls[i].b]=0;
q.push((point){ls[i].a,ls[i].b,0});
}
init();
int l=0,r=dis[xs][ys];
while(l<=r)
{
int mid=(l+r)>>1;
int t=check(mid);
if(t==-1)
r=mid-1;
else l=mid+1,ans1=mid,ans2=t;
}
printf("%d %d\n",ans1,ans2);
return 0;
}
Problem 3 :
题目来源:http://poj.org/problem?id=1837
背包型DP
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int c,g;
int p[110],w[110],dp[31][15010];//30M的空间限制
void solve()
{
dp[0][7500]=1;//初始化
for(int i=1;i<=g;i++)
{
for(int j=0;j<=15000;j++)//枚举平衡度
{
if(dp[i-1][j])
for(int k=1;k<=c;k++)
{
dp[i][j+w[i]*p[k]]+=dp[i-1][j];
}
}
}
}
int main()
{
scanf("%d%d",&c,&g);
for(int i=1;i<=c;i++)
scanf("%d",&p[i]);
for(int i=1;i<=g;i++)
scanf("%d",&w[i]);
solve();
printf("%d",dp[g][7500]);//dp[i][j]表示当用了i个钩码平衡度为j时的方案数
return 0; //7500=25*20*15由数据范围得出,设此平衡度时天平平衡
}