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

来源:互联网 发布:巨人网络收购alpha 编辑:程序博客网 时间:2024/05/24 02:38


相比较第一场,少了些许紧张,但是同样暴露了我们三人配合上的问题,开始被大神一句:第七道是一道水线段树,于是便直奔去搞线段树,结果这个题是过的人数最少的题之一~然后我们三人一人读一道题,甚至开始自己鼓捣怎么写,于是很长时间大家都在安静的搞自己觉得可能会搞出来的题,于是乎很长时间,都没有结果,然后大家慢慢弃疗,开始专注的考虑一道题,最终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 longusing 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 999999999using 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弃疗~
 

0 0
原创粉丝点击