由于昨天那场和牛客多校冲突了,就没打A轮。听说昨天题还很难。。。
而今天题目难度着实跨度太大,前三题都属于签到题,稍微想一想都能做出来。
但后面的题,怕是神仙题了。。。
弱弱的我用了1个半小时才A完3题,自然是滚粗复赛了。。。
下面看一下这几道题
-----------------------------------------------------------------------------------------------------------------------------------------------
1001 degree (hdu6380)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6380
刚开始看这道题,思路其实并不是特别明显。看了一会发现,首先,找出原图中度最大的点,对每个点dfs一次。每个点访问一次,复杂度O(n)。每次dfs时,sum++(也就是未与度最大的点联通的联通块数)(看看代码就懂了)。
当有k次操作时,每次相当于对度最大点所在的联通块减下来一个点,也就是度加1。
注意:答案最大为n-1,最后不要让答案超过n-1
代码:
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAXV = 2e5+10;
int d[MAXV];
vector<int> g[MAXV];
bool vis[MAXV];
int cnt=0;
int sum=0;
void dfs(int x)
{
vis[x]=true;
cnt++;
int len=g[x].size();
for(int i=0;i<len;i++)
{
if(!vis[g[x][i]])
dfs(g[x][i]);
}
}
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
int t;
int n,v,u,m,k;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<n;i++)
g[i].clear();
cnt=0;
sum=0;
for(int i=0;i<n;i++)
vis[i]=false;
for(int i=0;i<n;i++)
d[i]=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
d[u]++;
d[v]++;
}
int maxd=-1,maxid=-1;
for(int i=0;i<n;i++)
{
if(d[i]>maxd)
{
maxd=d[i];
maxid=i;
}
}
vis[maxid]=true;
for(int i=0;i<n;i++)
{
if(i!=maxid&&vis[i]==false)
{
dfs(i);
sum++;
}
}
sum+=k;
sum=min(n-1,sum);
printf("%d\n",sum);
}
return 0;
}
1004 p1m2(hdu6383)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6383
这道题还是很套路的。看到题面中最小值最大化 -> 果断二分。
二分每一个可能的答案,检查这个答案是否满足要求。
具体检查方法就是,看当前需要补得数和超过的数之间的关系,看代码就能懂。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
ll a[300010];
ll maxnum;
bool check(ll x)
{
ll bu,guo;
bu=0,guo=0;
for(int i=1;i<=n;i++)
{
if(a[i]<x)
{
bu+=x-a[i];
}
else if(a[i]>x)
{
guo+=(a[i]-x)/2;
}
}
if(guo<bu)
return false;
if(guo>=bu)
return true;
}
ll ans;
void b_search()
{
ll lb=0;
ll rb=maxnum;
while(lb<=rb)
{
ll mid=(lb+rb)/2;
if(check(mid))
{
ans=max(ans,mid);
lb=mid+1;
}
else
{
rb=mid-1;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
maxnum=0;
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
maxnum=max(maxnum,a[i]);
}
ans=0;
b_search();
printf("%I64d\n",ans);
}
return 0;
}
1006 rect(hdu6385)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6385
其实这道题才是全场最水的题,关键点在于题目中有个重要条件,任意两点不在同一行同一列。
所以说,直接看每一个点离4条边哪个进选哪个就好了(不会相交,没有必要证,可以自己画画)。
代码:
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
int t;
ll n,mx,my;
ll d1,d2,d3,d4;
ll x,y;
scanf("%d",&t);
ll sum;
while(t--)
{
sum=0;
scanf("%I64d%I64d%I64d",&mx,&my,&n);
for(int i=1;i<=n;i++)
{
scanf("%I64d%I64d",&x,&y);
d1=x;
d2=mx-x;
d3=y;
d4=my-y;
sum+=min(min(d1,d2),min(d3,d4));
}
printf("%I64d\n",sum);
}
return 0;
}
--------------------------------------------------------------------------------------------------------------------------------------------------
最后的一个多小时一直刚1002了,不过这道题过的人极少。。。
我写了个暴力,幻想着万一数据不强(不可能的),最后理所当然的T了。
今天其实打的还行吧,就是手(nao)慢(can)了点,明年再战。。。