A - 水题A
CodeForces - 106B
题意
电脑一共有三个属性和价格,如果一个电脑的三个属性都严格的小于其他的其中一个电脑,则这个电脑是过时,在不过时的电脑中选择价格最低的那个。。。
直接for循环遍历模拟
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
int a,b,c,d,id;
};
node a[105],b[105];
int tot;
int cmp(node x,node y)
{
return x.d<y.d;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d %d %d %d",&a[i].a,&a[i].b,&a[i].c,&a[i].d);
a[i].id=i;
}
int flag=0;
for(int i=1; i<=n; i++)
{
int flag=0;
for(int j=1; j<=n; j++)
{
if(i!=j)
{
if(a[i].a<a[j].a&&a[i].b<a[j].b&&a[i].c<a[j].c)
{
flag=1;
break;
}
}
}
if(!flag)
{
b[tot].a=a[i].a;
b[tot].b=a[i].b;
b[tot].c=a[i].c;
b[tot].d=a[i].d;
b[tot++].id=a[i].id;
}
}
sort(b,b+tot,cmp);
printf("%d\n",b[0].id);
return 0;
}
·
·
B - 水题B
CodeForces - 203B
题意
有一个n*n的格子,刚开始每个格子都是白色的,现在把m个格子屠城了黑色,有没有涂成一个3 * 3的黑色格子,如果没有输出-1,如果有输出第一个出现3 * 3格子的最少操作步数
思路
开一个新的数组a,每次涂一个格子在a数组上把这个格子周围包括这个格子本身的9个格子+1,如果有一个格子的值为9,那么就出现了一个以这个格子为中心的3 * 3的黑色格子
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int e[1005][1005];
int nex[8][2]= {{1,0},{0,1},{-1,0},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
int x,y,flag=0,a;
memset(e,0,sizeof(e));
for(int i=1; i<=m; i++)
{
scanf("%d %d",&x,&y);
e[x][y]++;
if(e[x][y]==9&&!flag)
{
flag=1;
a=i;
}
if(!flag)
{
for(int j=0; j<8; j++)
{
int tx=x+nex[j][0];
int ty=y+nex[j][1];
if(tx<=0||ty<=0||tx>n||ty>n)
continue;
else
e[tx][ty]++;
if(e[tx][ty]==9&&!flag)
{
flag=1;
a=i;
}
}
}
}
if(flag)
{
printf("%d\n",a);
}
else
printf("-1\n");
}
return 0;
}
C - 水题C
HDU - 2141
中文题意就不解释了。
思路就是把前两个货架的值两两和预处理出来,然后遍历第三个货架,在预处理的和中二分。。。
这个题简直卡死我了。。。wa了18发。。我竟然还有勇气交。。是的wa了18发后A了。。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
using namespace std;
int a[505],b[505],c[505];
int d[250003];
int main()
{
int x1,y1,z1,p=1,x,y,z;
int f;
while(~scanf("%d %d %d",&x1,&y1,&z1))
{
int flag=0;
if(x1<=0||y1<=0||z1<=0)
flag=1;
for(int i=1; i<=x1; i++)
{
scanf("%d",&a[i]);
}
for(int i=1; i<=y1; i++)
{
scanf("%d",&b[i]);
}
for(int i=1; i<=z1; i++)
{
scanf("%d",&c[i]);
}
int ans=0;
for(int i=1;i<=x1;i++)
for(int j=1;j<=y1;j++)
{
int k=a[i]+b[j];
d[ans++]=k;
}
sort(d,d+ans);
int T,n;
scanf("%d",&T);
printf("Case %d:\n",p++);
while(T--)
{
scanf("%d",&n);
if(flag)
{
printf("NO\n");
continue;
}
int flag1=0;
for(int i=1;i<=z1;i++)
{
int h=n-c[i];
int l=0,r=ans-1;
while(l<=r)
{
int mid=(l+r)/2;
if(d[mid]==h)
{
flag1=1;
break;
}
if(d[mid]>h)
r=mid-1;
else
l=mid+1;
}
}
if(flag1)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
·
·
D - 水题D
HDU - 1874
最短路的板子题,敲了一发板子就过了
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct node
{
int v,w,nex;
};
node e[20005];
int f[1005],n,m,tot;
int dis[305],book[305];
const int inf=0x3f3f3f3f;
void init()
{
tot=0;
memset(f,-1,sizeof(f));
memset(book,0,sizeof(book));
for(int i=0;i<n;i++)
dis[i]=inf;
}
void add(int u,int v,int w)
{
e[tot].v=v;
e[tot].w=w;
e[tot].nex=f[u];
f[u]=tot++;
}
int main()
{
int s,t,x,y,z;
while(~scanf("%d %d",&n,&m))
{
init();
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
scanf("%d %d",&s,&t);
dis[s]=0;
book[s]=1;
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=f[u];i!=-1;i=e[i].nex)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(book[v]==0)
{
q.push(v);
book[v]=1;
}
}
}
book[u]=0;
}
if(dis[t]<inf)
printf("%d\n",dis[t]);
else
printf("-1\n");
}
return 0;
}
·
·
E - 水题E
POJ - 3104
题意就不解释了。
思路:二分需要的时间,判断时间x内能不能让这N件衣服晾干:我们设一件衣服用吹风机的时间为x
则(mid-x)+x*k>=Ai,整理一下得x>=(Ai-mid)/(k-1),当k==1时,回发生除0错误,所以 k= =1时要特判一下
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
long long n,e[100005],k;
int F(long long mid)
{
long long ans=0;
for(long long i=1; i<=n; i++)
{
if(e[i]>mid)
{
long long t=e[i]-mid;
ans+=t/k;
if(t%k)
ans++;
}
}
if(ans<=mid)
return 1;
return 0;
}
int main()
{
while(~scanf("%lld",&n))
{
long long r=-1;
for(long long i=1; i<=n; i++)
{
scanf("%lld",&e[i]);
r=max(r,e[i]);
}
scanf("%lld",&k);
if(k==1)
{
printf("%lld\n",r);
continue;
}
k--;
long long ans=0,l=1;
while(l<=r)
{
long long mid=(l+r)/2;
if(F(mid))
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%lld\n",ans);
}
return 0;
}
·
·
F - 水题F
CodeForces - 612D
题意
给你n个线段,输出k个线段覆盖的区间
思路
看到这个题的时候,感觉是线段并的问题,但是其实没有这么麻烦,只是利用了线段并的思想,我们把左端点记为1,右端点记为-1,从左到右扫描,如果扫描值为k那么这个时候有k条线段同时覆盖,当第一次小于k时,也就是我们要记录的右端点了。。模拟一下就好
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
int flag,x;
};
node e[5000005];
struct Node
{
int x,y;
};
Node b[5000005];
int cmp(node x,node y)
{
if(x.x==y.x)
return x.flag>y.flag;
return x.x<y.x;
}
int main()
{
int n,k;
while(~scanf("%d %d",&n,&k))
{
int tot=0,x,y;
for(int i=1;i<=n;i++)
{
scanf("%d %d",&x,&y);
e[tot].x=x;
e[tot++].flag=1;
e[tot].x=y;
e[tot++].flag=-1;
}
sort(e,e+tot,cmp);
int sum=0,flag=0;
x=0;
for(int i=0;i<tot;i++)
{
x+=e[i].flag;
if(x>=k&&flag==0)
{
flag=1;
b[sum].x=e[i].x;
}
if(flag&&x<k)
{
flag=0;
b[sum++].y=e[i].x;
}
}
printf("%d\n",sum);
for(int i=0;i<sum;i++)
printf("%d %d\n",b[i].x,b[i].y);
}
return 0;
}
·
·
G - 水题G
CodeForces - 1051C
虽然是中文题意,但是我还是想说一下这个独一无二,是对于男生和女生单独而言的。。。如果女生手里只有一颗这个糖,那么对于女生而言就是独一无二的。。。比赛的时候,以为是对于男生女生一起而言。。。好难过。。。
思路:
对于只有一颗的糖,他可以作为独一无二的糖给男生或者女生;
对于有两颗的糖,有两种情况:
1)全都给男生或者女生,也就是对于结果没有任何影响
2)一颗给男生一颗给女生,这两颗糖对于男生女生而言都是独一无二的糖,对结果也没有任何影响
对于有三颗及以上的糖来说:
1)其中一颗糖给男生或女生,其余的都给对方,则拿到一颗糖的一方独一无二的糖数加一
2)全都给男生或者女生,对结果没有影响
综上:当只有一颗糖的数量为奇数,且没有三颗及以上的糖的时候,输出NO,其余情况都可以
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[105],e[105],c[105];
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(e,0,sizeof(e));
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
e[a[i]]++;
}
int x=0,y=0;
for(int i=1; i<=100; i++)
{
if(e[i]==1)
x++;
else if(e[i]>2)
y++;
}
if(x%2&&y==0)
printf("NO\n");
else
{
printf("YES\n");
if(x%2==0)
{
int s=0;
for(int i=1; i<=n; i++)
{
if(e[a[i]]==1)
{
if(s%2)
printf("A");
else
printf("B");
s++;
}
else
printf("A");
}
}
else
{
int s=0,flag=0;
for(int i=1; i<=n; i++)
{
if(e[a[i]]==1)
{
if(s%2)
printf("B");
else
printf("A");
s++;
}
else if(e[a[i]]>2&&!flag)
{
flag=1;
printf("B");
}
else
printf("A");
}
}
printf("\n");
}
}
return 0;
}
·
·
H - 水题H
POJ - 1821
这个连接就直接给原题连接吧。。(翻译的中文题意。。。根本看不懂,还好比赛的时候根本没看)
题意
一共有m个粉刷匠,一个长n的栅栏(每个栅栏编号1~n)
每个粉刷匠有三个值si,pi,li 分别代表着,这个粉刷匠坐在第si个栅栏前可以粉刷li个栅栏(必须是连续的并且包括第si个栅栏),粉刷一个栅栏可以赚pi元
问你这m个粉刷匠可以赚钱的最大值是多少
思路
设dp【i】【j】的意思是:第i个粉刷匠粉刷到第j个栅栏的时候能赚的最大钱是多少
那么dp【i】【j】可以转移的有三个方程
1)dp[i][j]=dp[i-1][j]:意思是,第i个粉刷匠没有刷栅栏,那么这个状态下得到的钱就是上一个粉刷匠粉刷的所赚的钱
2)dp[i][j]=dp[i][j-1]:第i个粉刷匠没有刷第j个栅栏
3)dp[i][j]=dp[i-1][k]+(j-k)*pi:第i-1个粉刷匠粉刷到底k个栅栏,第i个粉刷匠粉刷从k+1粉刷到第j个栅栏
所以,dp[i][j]=max(dp[i-1][j] , dp[i][j-1] , dp[i-1][k]+(j-k)*pi);
到这里基本的思路就理清楚了,但是在第三个状态下dp[i][j]=dp[i-1][k]+(j-k)*pi,我们发现还要枚举k,那么时间复杂度就太高了,当j不变的时候dp[i][j] = dp[i-1][j] + j * pi - k * pi,我们发现j * pi是不变的,我们只要找到dp[i-1][j] - k * pi的最大值就好。用优先队列维护一下
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct Node
{
int p,v;
Node(int V,int P)
{
p=P;
v=V;
}
bool operator <(const Node &a)const
{
return this->v<a.v;
}
};
struct node
{
int s,p,l;
};
node e[105];
int dp[105][20000];
int cmp(node x,node y)
{
return x.s<y.s;
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
for(int i=1;i<=m;i++)
scanf("%d %d %d",&e[i].l,&e[i].p,&e[i].s);
sort(e+1,e+1+m,cmp);
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++)
{
int si=e[i].s,pi=e[i].p,li=e[i].l;
priority_queue<Node>q;
for(int k=max(0,si-li);k<si;k++)
q.push(Node(dp[i-1][k]-pi*k,k));
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
if(j<si||j>=si+li)
continue;
while(!q.empty()&&q.top().p+li<j)
q.pop();
if(q.empty())
continue;
dp[i][j]=max(dp[i][j],q.top().v+pi*j);
}
}
printf("%d\n",dp[m][n]);
}
return 0;
}