您的位置:首页 > 其它

2015多校联合训练总结(2)

2015-07-27 19:46 323 查看
相比较第一场,少了些许紧张,但是同样暴露了我们三人配合上的问题,开始被大神一句:第七道是一道水线段树,于是便直奔去搞线段树,结果这个题是过的人数最少的题之一~然后我们三人一人读一道题,甚至开始自己鼓捣怎么写,于是很长时间大家都在安静的搞自己觉得可能会搞出来的题,于是乎很长时间,都没有结果,然后大家慢慢弃疗,开始专注的考虑一道题,最终ac了一道。所以在慢慢的训练中我们才会共同成长吧~~

下面是其中某些题的题解

A:http://acm.hdu.edu.cn/showproblem.php?pid=5300

题很长,过的人很少很少,放弃

B:http://acm.hdu.edu.cn/showproblem.php?pid=5301

题意:n*m的矩阵里面有一个1*1的小黑块,用大小不同的小矩形铺满n*m的矩形,不能覆盖小黑块,只能相接,同时这些小矩形必须满足至少有一边在大矩形的边框上,使得这些小矩形都尽量小,使得面积最大的小矩形面积最小,这个小矩形面积多大

思路:读题费了很长时间,“minimize the maximum areas of all apartments”,在图文并茂下终于读懂了,第一感觉就是一个机智题,大致找了一规律。就是最短边加1的一半,如果在黑块正好在正方形的正中间,那么就减一,预料中的wa了、、然后就开始考虑特殊情况,那就是类似于这种的


按照最初的思路,结果应该是2,但是明显的,不符合条件,所以我又用了另一种方法,求小黑块四个方向距离四边的最小值,并取四个最小值中的最大值,然后用这两种结果取最大值,就是结果,最终ac了

过程中还卡了很久,原因竟然是n和m弄反了。。。。TnT

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 1000005;
int main()
{
ll n,m,x,y;
ll a[10];
while(scanf("%lld %lld %lld %lld",&n,&m,&x,&y)!=EOF)
{
if(n==1&&m==1)
{
printf("0\n");
continue;
}
if(n==1||m==1||n==2||m==2)
{
printf("1\n");
continue;
}
a[0]=min(y-1,x);
a[0]=min(a[0],n-x+1);
//cout<<a[0]<<endl;
a[1]=min(x-1,y);
a[1]=min(m-y+1,a[1]);
//cout<<a[1]<<endl;
a[2]=min(x,m-y);
a[2]=min(a[2],n-x+1);
//cout<<a[2]<<endl;
a[3]=min(y,n-x);
a[3]=min(a[3],m-y+1);
//cout<<a[3]<<endl;
ll maxn=max(max(max(a[0],a[1]),a[2]),a[3]);
ll sum=(min(n,m)+1)/2;
if(n==m&&n%2&&x==(n+1)/2&&y==(n+1)/2)sum--;

printf("%lld\n",max(sum,maxn));
}
return 0;
}


C:http://acm.hdu.edu.cn/showproblem.php?pid=5302

题意:给你六个点,分别是白点度为0的有a1个,白点度为1的有a2个,白点度为2的点有a3个,黑色的度为0的点b1个,黑点度为1的点有b2个,黑色度为2的点有b3个,同时要求白点个数等于黑点个数,要求构造一个图满足这个条件

思路:若a2&1 或b2&1 则无解。度为1的点必须成对存在,在这只有0 1 2度数的图中。白色边和黑色边不相互影响,他们是独立的。总的边数为总度数/2 。即:(a2+a3*2)/2.

先构造白边度数为2的点,必然是(1,2)(2,3)(3,4)....(a3+1,a3+2)..如此下去,直到完成度数2的节点的构造。

再够着白边度数为1的点,(a3+3,a3+4) (a3+5,a3+6).......

最后白色边度数为0的点,(,)(,)...(a1+a2+a3,a1+a2+a3)

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int T;
int a[5],b[5];
int d[1000005];
int main()
{
scanf("%d",&T);
while(T--)
{
for(int i = 0; i<3; i++)
scanf("%d",&a[i]);
for(int i = 0; i<3; i++)
scanf("%d",&b[i]);
int sum = 0;
for(int i = 0; i<3; i++)
sum+=a[i];
if( (a[1]&1) || (b[1]&1) )
{
puts("-1");
continue;
}
if(sum==4)
{
puts("4\n1 2 0\n1 3 0\n2 3 1\n3 4 1");
continue;
}
printf("%d\n",a[1]/2+a[2]+b[1]/2+b[2]);
int t = 1;
while(a[2]!=-1)
{
printf("%d %d 0\n",t,t+1);
t++;
a[2]--;
}
t++;
while(a[1]!=2)
{
printf("%d %d 0\n",t,t+1);
t+=2;
a[1]-=2;
}

int tt = 0;
for(int i = 1; i<=sum; i+=2)
d[tt++] = i;
for(int i = 2; i<=sum; i+=2)
d[tt++] = i;

t = 0;
while(b[2]!=-1)
{
printf("%d %d 1\n",min(d[t],d[t+1]),max(d[t],d[t+1]));
t++;
b[2]--;
}
t++;
while(b[1]!=2)
{
printf("%d %d 1\n",min(d[t],d[t+1]),max(d[t],d[t+1]));
t+=2;
b[1]-=2;
}

}
}

D:http://acm.hdu.edu.cn/showproblem.php?pid=5303

题意:一个圆形环道上有n棵苹果树,从顺时针方向看,每个苹果树分别上距离原点分别有di米的位置,有ai个苹果,每次最多能拿k个苹果,若要把所有苹果都摘到原点,问最少需要走多少米

思路:如果道路不是环形的,那么就把道路平均截成两段贪心即可,但是这样有一个问题,就是有时候可能需要走整个环,但是可能想到的是这个环最多只会走1次,因为如果走两次的话,可以分别走两个半环, 接下来的处理两种思路,一种是左右两侧分别以每k个一组,剩下的分别采取1.走一圈,左边剩余的单独一回,2.走一圈,右边剩余的单独一回,3.左侧的单独走,右侧的单独走,三种方式找最小的。第二种是记录摘取每个苹果所需要的累计的路程,然后把最后一个作为所用路程的一半,暴力从左侧都包含,逐渐右移,再到全右侧,找了最小的。

代码:(第二种方法)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
using namespace std;
typedef long long ll;
int x[2111111];int n;
int l,k;

int a1[2111111],n1,a2[2111111],n2;
ll ans=0;
ll su1[2111111],su2[2111111];
int main()
{
int tes;
scanf("%d",&tes);
while(tes--){
int cnt;
scanf("%d%d%d",&l,&cnt,&k);
n=0;
while(cnt--){
int y,a;
scanf("%d%d",&y,&a);
for (int i=1;i<=a;i++)x[++n]=y;
}
k=min(k,n);
n1=n2=0;
for (int i=1;i<=n;i++)
if(x[i]*2<l)a1[++n1]=x[i];
else a2[++n2]=l-x[i];
sort(a1+1,a1+1+n1);
sort(a2+1,a2+1+n2);
su1[0]=su2[0]=0;
for (int i=1;i<=n1;i++)
{
if(i<=k)su1[i]=a1[i];
else su1[i]=a1[i]+su1[i-k];
//cout<<su1[i]<<endl;
}
for (int i=1;i<=n2;i++)
{
if(i<=k)su2[i]=a2[i];
else su2[i]=a2[i]+su2[i-k];//取第i个苹果所需要走的步数,su2[i-k]上一回取得时候所走的步数
//cout<<su2[i]<<endl;
}
ans=(su1[n1]+su2[n2])*2;
//cout<<ans<<endl;
for (int i=0;i<=n1 && i<=k;i++){//暴力从a2搜到了两侧都包含,再到全a1,找了最小的
int lef=n1-i,rig=max(0,n2-(k-i));
ans=min(ans,l+(su1[lef]+su2[rig])*2);
}
printf("%lld\n",ans);

}
return 0;
}


E:状压dp

F:http://acm.hdu.edu.cn/showproblem.php?pid=5305

题意:给你n个人,这n个人构成m对朋友,现在想要这n个人每个人都拥有相等的线上朋友和线下朋友,问能不能实现,如果不能输出0,否则输出有几种方式

思路:dfs搜索,分别假设第i对朋友是线上朋友,要努力保证线上朋友和线下朋友相等,以此类推,直到最后一个,如果这m对都满足,那么sum++,最后的sum就是所要求的结果

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <iomanip>
#include <queue>
#include <ctime>
#include <vector>
#include <ctype.h>
#define maxn 1005
#define ll long long
#define INF 999999999
using namespace std;

struct Edge
{
int a,b;
}e[35];

int n,m,f[10],up[10],dw[10];
int ans;

void dfs(int u)
{
if(u==m)
{
ans++;
return;
}
int a,b;
a=e[u].a;
b=e[u].b;
//cout<<a<<" "<<b<<endl;
f[a]--;
f[b]--;
up[a]++;
up[b]++;
if((f[a]&&f[b])||(!f[a]&& f[b] && up[a]==dw[a])||(!f[b] && f[a] && up[b]==dw[b])||(!f[a]&& !f[b] && up[a]==dw[a] && up[b]==dw[b]))
{
dfs(u+1);
}
up[a]--;
up[b]--;
dw[a]++;
dw[b]++;
if((f[a]&&f[b])||(!f[a] && f[b] && up[a]==dw[a])||(!f[b]&& f[a] && up[b]==dw[b])||(!f[a]&& !f[b]&& up[a]==dw[a] && up[b]==dw[b]))
{
dfs(u+1);
}
dw[a]--;
dw[b]--;
f[a]++;
f[b]++;
}

int main()
{
int t,k;
cin>>t;
while(t--)
{
cin>>n>>m;
memset(f,0,sizeof (f));
memset(up,0,sizeof(up));
memset(dw,0,sizeof(dw));
ans=0,k=1;
for(int i=0;i<m;i++)
{
cin>>e[i].a>>e[i].b;
f[e[i].a]++;
f[e[i].b]++;
}
for(int i=1;i<=n;i++)
{
if(f[i]%2!=0)
{
k=0;
break;
}
}
if(k==0)
{
cout<<0<<endl;
}
else
{
dfs(0);
cout<<ans<<endl;
}
}
return 0;
}


G:暴力线段树,开头听了大神言,小伙伴写了半个多小时,无结果,弃疗、、

H:FFT快速傅氏变换,复变中的傅氏变换都没学明白,对于FFT代码、、

I:http://acm.hdu.edu.cn/showproblem.php?pid=5308

题意:用n个n用+、-、*、/、()这几个符号得到24点

思路:暴力找规律,直接输出

代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
int n;
int main(){
//	freopen("data.in","r",stdin);
//	freopen("dataa.out","w",stdout);
while (scanf("%d",&n)!=EOF){
if (n>=15){
printf("1 + 2\n"); printf("3 + 4\n"); printf("5 + 6\n"); printf("7 + 8\n"); printf("%d + 9\n",n+1);
printf("%d / 10\n",n+2); printf("%d / 11\n",n+3); printf("%d / 12\n",n+4); printf("%d / 13\n",n+5);
printf("%d * %d\n",n+6,n+7); printf("%d * %d\n",n+8,n+9); printf("%d * %d\n",n+10,n+11); printf("14 - 15\n");
int now=n+13; for (int i=16;i<=n;i++){printf("%d * %d\n",i,now); now++;} printf("%d + %d\n",n+12,now); continue;
}
if (n>=12){
printf("1 + 2\n");
for (int i=1;i<=n*2-24;i++) printf("%d / %d\n",i*2+1,i*2+2); int num=n*4-46;
int now=n+1+n*2-24;
if (n!=12){
printf("%d - %d\n",n+1,n+2); now++;
for (int i=2;i<=n*2-24;i++){printf("%d - %d\n",now,n+1+i); now++;}
}
int k1=now;
printf("%d - %d\n",num+1,num+2); num+=3; now++;
for (int i=num;i<=n;i++){printf("%d * %d\n",i,now); now++;}
printf("%d + %d\n",k1,now); continue;
}
if (n>=10){
printf("1 + 2\n");
for (int i=1;i<=24-n*2;i++) printf("%d / %d\n",1+2*i,2+2*i);
printf("%d + %d\n",n+1,n+2); int now=n+26-n*2;
for (int i=2;i<=24-n*2;i++) {printf("%d + %d\n",n+1+i,now); now++;}
if (n==10) continue;
printf("7 - 8\n"); printf("17 * 9\n"); printf("18 * 10\n"); printf("19 * 11\n"); printf("20 + 16\n"); continue;
}
if (n==9){
printf("1 + 2\n"); printf("3 + 10\n"); printf("4 / 5\n"); printf("6 / 7\n"); printf("8 / 9\n");
printf("11 - 12\n"); printf("15 - 13\n"); printf("16 - 14\n"); continue;
}
if (n==8){
printf("1 + 2\n"); printf("3 + 9\n"); printf("4 - 5\n"); printf("6 * 11\n"); printf("7 * 12\n");
printf("8 * 13\n"); printf("10 + 14\n"); continue;
}
if (n==7){
printf("1 * 2\n"); printf("3 / 4\n"); printf("5 + 6\n"); printf("8 - 9\n"); printf("11 / 10\n"); printf("12 * 7\n"); continue;
}
if (n<=3){printf("-1\n"); continue;}
if (n==6){
printf("1 * 2\n"); printf("7 - 3\n"); printf("8 - 4\n"); printf("9 - 5\n"); printf("10 + 6\n"); continue;
}
if (n==5){
printf("1 / 2\n"); printf("6 / 3\n"); printf("4 - 7\n"); printf("5 * 8\n"); continue;
}
if (n==4){
printf("1 * 2\n"); printf("3 + 5\n"); printf("4 + 6\n"); continue;
}
}
return 0;
}

J:DP弃疗~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: