20151003&&20151004题解

来源:互联网 发布:淘宝卖家发布宝贝教程 编辑:程序博客网 时间:2024/04/25 23:10

HZ集训日 day1:距离CCF[noip2015仅31days]

番外篇:

 话说今天刚考完试,考试成绩就发了下来,不过考完试我们就去集训了,先来公布小蒟蒻[蒟蒻:一种植物..后来被人们形容成比较弱的人]的考试成绩吧,语文106[话说这次语文脱坑也是意料之中],数学131[QAQ第11题排除只剩下CD还选错了],英语124[...不作任何评价,看着悲催的二卷我无语了],物理98[涂错俩选择应该106...],化学84[不知是否要补化学作业,那么难做的选择就错俩才考了84,真是个悲剧,原谅我自嘲一下],话说集训日第一天物理老师趁我不在,又提起我的成绩。。。。很无语

生物[选择还是硬,扣一分,又到了烦人的二卷了...扣扣扣扣....直到75分满分90..]总分618超过了曾经年级190-的LGL..;

一句话结束 革命尚未成功,同志仍需努力

好了..转入正题






 

先写一下昨天考试的酱油记吧

Day1 80  Day2 70还算是给自己了一个交代:


先来写一下day1吧

找伙伴(partner)

 

在班级里,每个人都想找学习伙伴。

伙伴不能随便找,都是老师固定好的,老师给出要求:伙伴要凭自己实力去找。

老师给每个人发一张纸,上面有数字。假设你的数字是w,那么如果某位同学手中的数字的所有正约数之和等于w,那么这位同学就是你的小伙伴。

Input

输入包含n组数据(最多100组)

对于每组测试数据,输入只有一个数字w。

Output

对于每组数据输出两行,第一行包含一个整数m,表示有m个伙伴,第二行包含相应的m个数,表示伙伴的数字。注意:小伙伴的数字必须按照升序排列。

SampleInput

42

SampleOutput

3

2026 41

HINT

  100%的数据,有w<=2*10^9

时间限制:1s

 

我是数学蒟蒻,一遇见数学果断打暴力,这个题因为没有小数据,得了0分

我先不写这个题的题解

若急需题解请参考

http://blog.csdn.net/lglin000/article/details/48876191;
 

 

第 2题  我们爱几何 (geometry)

 

AngryBacon 和 ftiasch 是好朋友。ftiasch 酷爱几何,于是 AngryBacon 经常会为 ftiasch 出一些几何 题。这次,他又出了一道题目:

 

给出平面上的 N 个整点,AngryBacon 想选取这 N 个点中的 K 个点,连成一个正 K 边形。 正 K 边形的定义为边数为 K 的多边形,要求 K >=3,各边相等,各角也相等。 AngryBacon 想知道他最多能取多少个点。

 

输入格式

 

第一行,1 个整数 T , 表示数据组数。接下来是T 组数据。 每组数据的第一行包含一个整数 N,表示给定的点数。 接下来的N 行每行两个整数,分别表示一个点的 x; y 坐标。

 

输出格式

 

对于每组数据,输出一行,包含一个整数,表示算最多可取的点数。如果无法连成任何的合法正多边 形,则输出 1。

输入样例

2

5

1 0

0 1

1 2

2 1

1 1

4

0 1

1 2

2 1

1 1

输出

4

-1

 

Solution:

对于n<=10,只要暴力枚举所有排列就好了。

对于n<=20,稍有基础的同学应该能想到一个O(n*n*2^n) 的 DP,即f[s][i][j]表示前i个位置填完了,用了状态为s的人(0<=s<2^n),其中j个人感到开心的方案数。 使用滚动数组滚动i这一维可以做到空间复杂度O(2^n*n)。 这时候你可能觉得这个时间复杂度对于n=20有些太大(事实上在评测机上只用0.5秒即可出解),但此时应该注意到输入的n、k只有20*20=400种,完全可以在本地把答案算好提前写到源程序里去。 这个常见的技巧叫做打表,如果你以前没有听说过,现在可以把它加入骗分技巧大全中。

对于n=1000,是本试中最难的问题,难度稍高于noip一等。需要掌握一点基本的容斥原理,我尽量解释的详细些,实在不懂去理解程序。 因为给定的是环,首先枚举前两位填的人是不是一定开心(如果枚举为开心的话继续枚举具体哪个人坐在上面),这样断环为链了,枚举量大概为14。 接下来f[i][j][mask]表示前i个位置中其中j个位置上的人必须开心(剩下的i-j个人先不考虑,最后可能开心也可能不开心),并且i+1和i+2这两个人是否已经入座(用0..3的mask表示)的方案数。转移则枚举坐在i+1这个位置的人是否开心,如果开心枚举谁坐在上面,转移到f[i+1][j+1][mask']。如果不开心则转移到f[i+1][j][mask'']。 dp到最后,和开头枚举的断环为链的状态不冲突即可视作合法。接下来对所有合法的状态进行容斥。

首先看f[n][n]这个状态,它的意义是所有位置上的人都开心的方案数。我们倒序枚举i,依次算出ans[i]为恰好i个人开心的方案数,可知ans[n]=f[n][n]。 我们假设已经算出了ans[k+1]到ans[n],现在要计算ans[k]。 再看f[n][k]这个状态,它的意义是n个位置里先选择了k个位置强制其开心,再为其选择谁坐在上面的方案数。有n-k个人没有考虑,我们不如假设其随便坐ans[k]=f[n][k]*(n-k)!。注意到这个时候ans[k]的答案是不对的,有些大于k个人开心的情况被重复计数了,于是要容斥。我们枚举大于k的已经计算好的ans[l],考虑ans[l]在ans[k]里被计数了多少次,可以发现被计数了C(l,k)次,于是ans[k] = ans[k] - ans[l] * C(l,k)。这样我们就利用容斥算出了ans[k]。

将多个初始状态的ans累加即得到答案。复杂度O(n^2)。

#include<cstdio>#include<algorithm>using std::sort;const int MAXN=1010UL;int n,T;class node{public:int i,j;}a[MAXN];inline int in(){char c=getchar();int x=0;while(c<'0'||c>'9')c=getchar();for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';return x;}inline int comp(const node &a,const node &b){return a.i==b.i?(a.j<b.j):a.i<b.i;}//排序可以搜索inline bool check(int x,int y){    int l=1,r=n,m=(l+r)>>1;//二分思想。。。枚举点 看是否成立 成立 4 不成立 -1    if((a[m].i==x)and(a[m].j==y)) return true;    while(l<r){        if((a[m].i<x)or(a[m].i==x&&a[m].j<y)) l=m+1; else r=m-1;        m=(l+r)>>1;        if((a[m].i==x)and(a[m].j==y)) return true;    }return false;}inline bool g(){    sort(a+1,a+n+1,comp);    for(int i=1;i<=n;i++)        for(int j=i+1,x,y;j<=n;j++){            x=a[i].i-a[j].i,y=a[i].j-a[j].j;//上下左右搜索;            if((check(a[j].i-y,x+a[j].j))and(check(a[i].i-y,x+a[i].j))) return true;            x=-1*x,y=-1*y;            if((check(y+a[j].i,a[j].j-x))and(check(y+a[i].i,a[i].j-x))) return true;        }    return false;}int main(){    T=in();    while(T){T--,n=in();        for(int i=1;i<=n;i++)scanf("%d%d",&a[i].i,&a[i].j);        if(g()) putchar('4');else putchar('-'),putchar('1');        putchar('\n');    }return 0;}

后记 本题是我唯一一道考场上没有打代码的题,代码是一个一个字母挤出来的...很不容易 向所有努力工作的HZOIer致敬!

第三题 我们爱序列 (sequence)

 

AngryBacon 非常喜欢序列,与序列有关的一切都喜欢。

 

AngryBacon 面前摆着一个长度为 N 的序列,每个元素为不超过 M 的正整数。

 

AngryBacon 会使用 Q 次魔法,每次魔法的内容为一对不超过 M 的正整数 a; b,表示将序列中所有 为a 的数改写为 b

 

AngryBacon 想知道在最后他心爱的序列变成了什么样。

 

输入格式

 

第一行,包含三个整数 N; M; Q,意义如上所述。

 

第二行,包含 N 个整数 A1; A2; : : : ; AN ,表示初始序列。 接下来的Q 行,每行两个整数 a; b,意义如上所述。

 

输出格式

输出一行,包含 N 个整数,表示最后序列的形态

 

样例输入

5 5 3

1 2 34 5

3 1

4 3

1 5

样例输出

5 2 53 5

我这道题并没有想出正解,而是比别人多想了一下别人都用的O(n*q)效率的算法而我是用的O(n*m)的效率于是就得了60分 不过还是没有YMX和LGL高...

蒟蒻终究是蒟蒻啊..[话说LGL这道题用tarjan的思想得了100分..膜拜啊]

Solution

耐心想想,其实就是一个Union-Set[并查集],尽管考场上想到题目具有并查集的性质,但是这个并查集实在是不好打也不好想

对于n,q<=1000,暴力模拟不多讲。

对于m<=20,有一个非常显然的O(m*q+n)的做法,对每种数字c,我们记录color[c]表示初始数字为c的位置现在变成了什么数字,每次修改(a,b)只要枚举所有的m种数字,将所有color为a的改为b即可。 对于n,m,q<=1000000,则是一个非常正统的基础数据结构应用。我们使用并查集,n个位置每个位置都建立一个节点,m种颜色也都建立一个节点。对于初始的A[x]=y,我们将位置x的节点的父亲设为颜色y的节点。 对于一次修改(a,b),我们将颜色a的节点的父亲设为颜色b的节点,并对颜色a新建一个单节点。对于最后的输出,对于每个位置只要求出它所在的并查集的根是代表的哪个颜色即可。 注意对于a=b的情况的处理。


//上代码!Rank1 #include<cstdio>#define MAXN 5000100ulint n,m,q,fa[MAXN];int color[MAXN],pos[MAXN],tot;inline int find(int x){if(fa[x]==x)return x;fa[x]=find(fa[x]);return fa[x];}inline int in(){    char c=getchar();int x=0;    while(c<'0'||c>'9')c=getchar();for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';    return x;}int main(){//  freopen("sequence.in","r",stdin),freopen("sequence.out","w",stdout);    n=in(),m=in(),q=in(),tot=n+m;    for(int i=1;i<=m;i++)        fa[i]=color[i]=pos[i]=i;    for(int i=1,x;i<=n;i++)        x=in(),fa[m+i]=x;    for(int i=1,x,y;i<=q;i++){        x=in(),y=in();        if(x^y)            fa[color[x]]=color[y],color[x]=++tot,pos[color[x]]=x,fa[color[x]]=color[x];    }    for(int i=m+1;i<=n+m-1;i++)  printf("%d ",pos[find(i)]);    printf("%d",pos[find(n+m)]);    return 0;}

时间紧任务重,今天本来想总结day2的考试题,LHB留的任务太重了,不过因为优先要完成师傅的任务...所以今天只能停滞在day1了

其实这两次考试,大家都拉不开差距,为什么大家的得分都那么高呢,还是比谁敢于想,善于去挑战思维,也许这就是奥赛给我们带来的最大的benefit吧.=

每日一语:自己选择的路,即使跪着,也要走完.


0 0
原创粉丝点击