9.14模拟试题

NOIP 2017 全真模拟冲刺

                                           ---dawn                                        

题目名称

临江仙 旧梦

长命女

春江花月夜

题目类型

dream

young

moon

可执行文件名

dream

young

moon

输入文件名

dream.in

young.in

moon.in

输出文件名

dream.out

young.out

moon.out

每个测试点时限

2.0s

1.0s

1.0s

内存限制

256 MB

128 MB

128 MB

测试点数目

10

10

10

每个测试点分值

10

10

10

试题背景:我国是文化古国,悠悠五千年给我们带来了许多诗词精粹。今天就让我们回味精美诗词,走向AK殿堂!

注意事项

  1. 文件名(输入和输出文件名) 必须是英文小写。
  2. 若无说明,对比方式均为忽略行末空格及文末回车的全文比较。
  3. C/C++中函数main()的返回值必须是int,程序正常结束的返回值必须是0。
  4. 评测环境为cena  注意:windows下long long输出请使用 %I64d。
  5. 编译时不打开任何优化选项。

6.嗯,就酱。题目难度除最难的题其余在普及组。

另:题目难度与题目顺序无关!

 

T1 临江仙 旧梦

 

题目背景

闻道故园花陌,今年奼紫嫣红。扬帆直渡水千重。东君何解意,送我一江风。

还是昔时庭院,终得醉卧花丛。残更惊醒月明中。流光如旧岁,多少梦成空。

 

题目描述

#define goodcatdog gcd

#define important i

#define judge  j

神说 每个梦想就是一轮月亮,高高地孤寂地挂在清冷的夜空。为了让月亮不再孤独,灯神给她找了好多好多伴儿。现在天空上就有n轮月亮啦!

月亮在天上跟相邻的伙伴玩够以后,就开始想要去找其他月亮玩,灯神为了让月亮变得更聪明,下了一个规定:若两个月亮编号分别为important和judge,若important ,judge满足goodcatdog(important,judge)>β,则important,judge就可以联通。

现在来了一个垃圾神叫J乌拉,他想知道编号为x的月亮和编号为y的月亮是否联通,聪明的你能帮帮它吗????

输入描述

第一行为一个数T,表明有T组测试数据

四个个数n,β,x,y;

输出描述

x,y联通,输出YeS,否则输出No

样例输入 

1

12 2 8 9

样例输出

YeS

数据范围:

对于30%的数据 n<=10

对于50%的数据 n<=15

对于第六个测试点 n<=65432

对于第七,八个测试点 n<=999999

对于100%的数据 β<=n<=1000000;T<=4;x,y<=n<=10000000

 

问两个点是否联通,看到这个题后我想到的就是tarjan求强联通分量。

然后我们考虑什么情况下连边,我们总不能暴力枚举每一个点计算它们的gcd然后再连边吧,n^2枚举填边,不T死才怪呢!

我们考虑题目中说的是如果两个点的gcd大于一个给定的值,那么连边。有一个显而易见的东西为两个数的最大公约数,一定同为他们的因子,那么我们是不是可以枚举因子,然后进行填边呢?!答案显然是肯定的。

我们从k+1开始枚举因子,(为什么是k+1??因为题目中说的是最大公约数大于k的而非等于),然后将这个因子与他的倍数连边,这样的话与他相连的点的最小公约数一定是当前枚举到的因子k。这样的话就可以保证具有大于k的最大公约束的两个点一定在一个强连通分量里

然后我们在来判断给出的两个点x,y是否在一个强连通分量里不就好了吗??

tarjan(慢死、、、)

但是我们如果自己出个极限数据的话,就会发现他连边的时候都要跑一分多钟,显然这是不行的。

我们就要想一个好点的算法来代替tarjan,问两个点是否联通,除了tarjan还有一个算法叫并查集(蒟蒻太渣,只能想到这两种做法,那就用并查集做吧、、)

我们在并查集里将tarjan里的连边改成将这几个点放在一个并查集里,这样就可以将连边的复杂度省去,是不是很简单明了??

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 11000000
using namespace std;
int q,t,n,m,x,y,fa[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int find(int x)
{
    if(fa[x]==x) return x;
    fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    freopen("dream.in","r",stdin);
    freopen("dream.out","w",stdout);
//    scanf("%d",&t);
    t=read();
    while(t--)
    {
        n=read(),m=read(),x=read(),y=read();
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=m+1;i<=n;i++)
        {
            int fx=find(i);
            for(int j=i;j<=n;j+=i)
            {
                int fy=find(j);
                fa[fy]=fx;
            } 
        }      
        if(find(x)==find(y)) printf("YeS\n");
        else printf("No\n");
    }
    return 0;
}
并查集

 

 

T2 长命女

 

题目背景

夏夜宴,绿酒一杯歌一遍

再拜陈三愿:

一愿郎君千岁;

二愿妻妾常健;

三月如同梁上雕燕,

你我常相见

 

题目描述

给定一个r*c的矩阵,在这个矩阵中有...一棵树!这棵树上有n间小屋,每间小屋都有v[i]个松果,两个小屋之间有一条双向树枝相连。

小浪是一只特别懒的小松鼠,他希望知道从每间小屋向外扩展γ步范围内最多能拿到多少松果,不聪明的你可以帮帮他吗????

输入描述

第一行 r,c

第二行 n,γ

以下n-1行 x,y有连边

最后一行n个数 表示每个小屋的松果数目。

输出描述

n行,每行为第i个小屋最多能拿到多少松果

样例输入

8 8

6 2

5 1

3 6

2 4

2 1

3 2

1

2

3

4

5

6

 

 

 

样例输出

15

21

16

10

8

11

 

数据范围

对于10%的数据:n<=10,r<=c<=50

对于40%的数据:n<=1000

对于100%的数据:n<=100000;0<=v[i]<=1000;γ<=20;r<=1000000,c<=1000000

 

对于40%的数据我们用爆搜是可以过得

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 210000
using namespace std;
bool vis[N];
int head[N],v[N];
int n,m,r,c,x,y,tot,ans;
long long read()
{
    long long x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int to,next,from;
}edge[N<<1];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
void dfs(int x,int s)
{
    if(s>m) return ;
    ans+=v[x];
    vis[x]=true;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(!vis[t]) dfs(t,s+1);
    }
    vis[x]=false;
}
int main()
{
    freopen("young.in","r",stdin);
    freopen("young.out","w",stdout);
    r=read(),c=read();
    n=read(),m=read();
    for(int i=1;i<n;i++)
    {
        x=read(),y=read();
        add(x,y),add(y,x);
    }
    for(int i=1;i<=n;i++)
      v[i]=read();
    for(int i=1;i<=n;i++)
    {
        ans=0;dfs(i,0);
        printf("%d\n",ans);
    }
    return 0;
}
40分爆搜

 然而正解是树形dp

 我们用一个数组sum[i][j]表示从i节点扩展j步可以得到的果子数,我们可以用dfs预处理处每一个点到达第j层可以得到的果子数。

怎么预处理??我们对与一个节点进行扩展,当前点走j步可以获得的果子数等于他的子节点走j-1步获得的果子数。

当然我们这个地方处理出来的是仅到当前层的果子数,也就是说我们处理出来的不是到达当前层的所有的果子数,这样的话我们在后面的时候要对于每一个点处理出该节点到达j层的所有果子数也就是将每一层的果子数累加起来。

由于我们处理的时候是以当前节点为父亲节点更新的,也就是说我们这个地方没法加上他的父亲节点以及其另一个分支上的,我们就要想办法解决这个问题,我们将当前点的值加上当前点的父亲走j-1(他要往外扩展j步,他到他父亲走1步)步可以得到的果子数,但是这样的话我们一定会累加一部分值,这部分为当前点所在的分支往下走j-2步能得到的果子数,我们要减去这一部分值才为最终答案

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 210000
using namespace std;
bool vis[N];
int head[N],fa[N],v[N],sum[N][30];
int n,m,r,c,x,y,tot,ans;
long long read()
{
    long long x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int to,next,from;
}edge[N<<1];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
void dfs(int x,int pre)
{
    fa[x]=pre;
    sum[x][0]=v[x];
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(t==pre) continue;
        dfs(t,x);
        for(int j=1;j<=m;j++)
         sum[x][j]+=sum[t][j-1];
    }
}
int get(int x)
{
    int ans=sum[x][m],t=m;
    for(;x!=1&&t;x=fa[x])
    {
        ans+=sum[fa[x]][--t];
        if(t) ans-=sum[x][t-1];
    }
    return ans;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<n;i++)
    {
        x=read(),y=read();
        add(x,y),add(y,x);
    }
    for(int i=1;i<=n;i++)
      v[i]=read();
    dfs(1,-1);
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      sum[i][j]+=sum[i][j-1];
    for(int i=1;i<=n;i++)
      printf("%d\n",get(i));
    return 0;
}
树形dp

 

T3 春江花月夜(AK好题)

 

题目背景

春江潮水连海平,海上明月共潮生。滟滟随波千万里,何处春江无月明!

江流宛转绕芳甸,月照花林皆似霰;空里流霜不觉飞,汀上白沙看不见。

江天一色无纤尘,皎皎空中孤月轮。江畔何人初见月?江月何年初照人?

人生代代无穷已,江月年年只相似。不知江月待何人,但见长江送流水。

白云一片去悠悠,青枫浦上不胜愁。谁家今夜扁舟子?何处相思明月楼?

可怜楼上月徘徊,应照离人妆镜台。玉户帘中卷不去,捣衣砧上拂还来。

此时相望不相闻,愿逐月华流照君。鸿雁长飞光不度,鱼龙潜跃水成文。

昨夜闲潭梦落花,可怜春半不还家。江水流春去欲尽,江潭落月复西斜。

斜月沉沉藏海雾,碣石潇湘无限路。不知乘月几人归,落月摇情满江树。

 

题目描述

小春和小江是两个很好的朋友,他们都信奉灯神教。有一天,小春突发奇想,学习起了莫比乌斯反演,恰好在这天,小江也突发奇想,学起了快速傅里叶变换。可是莫比乌斯反演比快速傅里叶变换字数多啊,于是乎小春就比小江学得快。

小春非常得意,利用所学知识给小江出了一倒防AK好题:已知在这个宇宙中有n个太阳和n个月亮,由于宇宙之神--灯神是一个喜爱数学的神,所以他就规定了n属于数域P。灯神把整个宇宙抽象成了一个二维平面坐标系,对于每个太阳和每个月亮,都有自己的一个坐标xi,yi 坐标也是数域成员。如果一个太阳想去找一个月亮玩,那么他只能往东面或者南面飞。月亮是不能动哒!飞行单位距离为1,他就会消耗的花费(其中p,q分别为斐波那契数列第100007 100000007项对1000000007取模的值) 灯神想知道怎么让每个太阳都能找到某个月亮玩使得花费最小(一个月亮只能被找一次)?小江一下子就被难倒了,询问聪明的你,那么聪明年轻帅气漂亮颜值居高无比的你能帮助他解决这个问题吗?(保证答案在long int的十分之一范围内)。

题目提示

1.数域定义 设F是一个数环(S是复数集的非空子集,如果S中的数对任意两个数的和、差、积仍属于S,则称S是一个数环。),如果对任意的a,b∈F而且a≠0, 则b/a∈F;则称F是一个数域。著名的域有:Klein四元域。

数域性质 任何数域都包含有理数域Q。即Q是最小的数域。

证明:F必有一个非零元素a.由于F为数环,所以0 = a - a属于F1 = a/a 属于F0和1都属于F那么2 = 1+13 = 2+1。。。。自然数N都属于F-n = 0 - n 也属于F故整数集合Z都属于F那么a/b 也属于F(其中a,b为整数)这样,任何一个数域都包含Q

2.莫比乌斯反演

卷积:令d|n表示d能整除n,比如 2|4 (=.=)定义关于整数的函数F(n)然后定义G(n)=Σ(F(d)) (其中d|n)  

反演原式:G(n)=Σ(F(d))(其中d|n)  

反演公式:F(n)=Σ(U(n/d)*G(d))这里U是莫比乌斯函数,他是每一项 G(d) 的系数。

3.欧拉函数:      

其中p1, p2……pnx的所有质因数,x是不为0的整数。

φ(1)=1(唯一和1互质的数(小于等于1)就是1本身)。

 

 

输入描述

第一行为一个正整数n,表示天月亮的数量(太阳的数量与之相等)。接下来n行,每行两个整数xi和yi,表示太阳的坐标。规定向东向北为x,轴正方向。接下来n行,每行两个数a和b,示月亮的坐标。

输出描述

第一行包含一个数,表示最小的花费。答案对斐波那契数列的第100000007项取模。

样例输入

3

3 5

1 2

4 3

6 3

5 2

2 1

样例输出

9

数据范围

对于30%的数据 n<=300

对于第四,五个测试点 n<=20000

对于第六,七,八个测试点 n<=25000

对于100%的数据 n<=3 0 0 0 1;0<=xi,yi<=1 0 0 0 0 0,0<=a,b<=1 0 0 0 0 0.

保证答案存在。

 

 这道题是很好的一道                            阅读理解题、、、、、、

我们读题目,提取题目核心内容,题目要让我们求得是每一个太阳到月亮的最小花费,最小花费为距离乘以单位距离内的花费。

是不是在看到题目单位距离内的花费的公式的时候已经要晕了,啊啊啊,这是什么鬼啊?!

你再仔细看看那个公式你会发现一个很有趣的事情,你会发现这个公式我们可以将其化简为1.也就是说单位距离花费为1

剩下的工作就是求最短距离了,我们画一个图以后会发现一个更有趣的事情,每个太阳只能向南和东走,也就是说每一个太阳只能跟他东南方的月亮有联系,设太阳的坐标为(x1,y1),月亮的坐标为(x2,y2),他们两个之间的距离为(x2-x1)+(y1-y2),讲这些距离累加起来最终的值为所有x2的和减去所有x1的和加上所有y1的和减去所有y2的和。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
long long x,y,ans;
long long read()
{
    long long x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int main()
{
    freopen("moon.in","r",stdin);
    freopen("moon.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        x=read(),y=read();
        ans-=x; ans+=y;
    }
    for(int i=1;i<=n;i++)
    {
        x=read(),y=read();
        ans+=x; ans-=y;
    }
    printf("%I64d",ans);
    return 0;
}
AC代码

 

 

 

附加题:因为某两位大佬已经提前知道了某些std 所以需要一道令人神清气爽的附加题来陶冶大佬的情操(其他同学可以无视 但如果提前AK可以做做玩 评测只测前三题,T4 A了有糖吃)

 (看看吧,蒟蒻太笨就不做了、、、)

 

T4 洛神赋(hkd好题)

文件名:god

输入输出:god.in/out

 

题目背景

黄初三年,余朝京师,还济洛川。古人有言,斯水之神,名曰宓妃。感宋玉对楚王神女之事,遂作斯赋。其辞曰:

余从京域,言归东藩。背伊阙,越轘辕,经通谷,陵景山。日既西倾,车殆马烦。尔乃税驾乎蘅皋,秣驷乎芝田,容与乎阳林,流眄乎洛川。于是精移神骇,忽焉思散。俯则末察,仰以殊观,睹一丽人,于岩之畔。乃援御者而告之曰:尔有觌于彼者乎?彼何人斯?若此之艳也!御者对曰:臣闻河洛之神,名曰宓妃。然则君王所见,无乃日乎?其状若何?臣愿闻之。

余告之曰:其形也,翩若惊鸿,婉若游龙。荣曜秋菊,华茂春松。仿佛兮若轻云之蔽月,飘摇兮若流风之回雪。远而望之,皎若太阳升朝霞;迫而察之,灼若芙蕖出渌波。秾纤得衷,修短合度。肩若削成,腰如约素。延颈秀项,皓质呈露。芳泽无加,铅华弗御。云髻峨峨,修眉联娟。丹唇外朗,皓齿内鲜,明眸善睐,靥辅承权。瑰姿艳逸,仪静体闲。柔情绰态,媚于语言。奇服旷世,骨像应图。披罗衣之璀粲兮,珥瑶碧之华琚。戴金翠之首饰,缀明珠以耀躯。践远游之文履,曳雾绡之轻裾。微幽兰之芳蔼兮,步踟蹰于山隅。

于是忽焉纵体,以遨以嬉。左倚采旄,右荫桂旗。壤皓腕于神浒兮,采湍濑之玄芝。余情悦其淑美兮,心振荡而不怡。无良媒以接欢兮,托微波而通辞。愿诚素之先达兮,解玉佩以要之。嗟佳人之信修,羌习礼而明诗。抗琼[王弟]以和予兮,指潜渊而为期。执眷眷之款实兮,惧斯灵之我欺。感交甫之弃言兮,怅犹豫而狐疑。收和颜而静志兮,申礼防以自持。

于是洛灵感焉,徙倚彷徨,神光离合,乍阴乍阳。竦轻躯以鹤立,若将飞而未翔。践椒涂之郁烈,步蘅薄而流芳。超长吟以永慕兮,声哀厉而弥长。

尔乃众灵杂遢,命俦啸侣,或戏清流,或翔神渚,或采明珠,或拾翠羽。从南湘之二妃,携汉滨之游女。叹匏瓜之无匹兮,咏牵牛之独处。扬轻袿之猗靡兮,翳修袖以延伫。体迅飞凫,飘忽若神,凌波微步,罗袜生尘。动无常则,若危若安。进止难期,若往若还。转眄流精,光润玉颜。含辞未吐,气若幽兰。华容婀娜,令我忘餐。

于是屏翳收风,川后静波。冯夷鸣鼓,女娲清歌。腾文鱼以警乘,鸣玉鸾以偕逝。六龙俨其齐首,载云车之容裔,鲸鲵踊而夹毂,水禽翔而为卫。

于是越北沚。过南冈,纡素领,回清阳,动朱唇以徐言,陈交接之大纲。恨人神之道殊兮,怨盛年之莫当。抗罗袂以掩涕兮,泪流襟之浪浪。悼良会之永绝兮。哀一逝而异乡。无微情以效爱兮,献江南之明。虽潜处于太阳,长寄心于君王。忽不悟其所舍,怅神宵而蔽光。

于是背下陵高,足往神留,遗情想像,顾望怀愁。冀灵体之复形,御轻舟而上溯。浮长川而忘返,思绵绵督。夜耿耿而不寐,沾繁霜而至曙。命仆夫而就驾,吾将归乎东路。揽騑辔以抗策,怅盘桓而不能去。

题目描述

hey 孩子!恭喜你已经成功进入AK殿堂,如果你想要比平常人更多的宝藏,那么你就要背更多的文章!那么就请到墓地许愿吧!

小智障 hkd负责看管一片墓地,墓地可以看作一个二维平面。墓地上有 n 座墓碑,编号 1,2,3,…,n每座墓碑可以看作平面上的一个点,其中第 i 座墓碑 (1≤i≤n) 位于坐标 (xi,yi)。任意两座墓碑的坐标均不相同。

老司机 小小鱼(xxy) 从原点 (0,0) 驾车出发,进行若干轮行动。每一轮,小小鱼(xxy) 首先选择任意一个满足以下条件的方向:

为左、右、上、左上 45°、右上 45° 五个方向之一。沿此方向前进可以到达一棵他尚未被盗的墓。完成选择后,小小鱼(xxy) 沿该方向直线前进,必须到达该方向上距离最近的尚未被盗的墓,在墓前许愿并继续下一轮行动。如果没有满足条件的方向可供选择,则停止行动。他会采取最优策略,在尽可能多的墓前许愿。若最优策略不唯一,可以选择任意一种。不幸的是,小智障 hkd发现由于墓地土质松软,老司机 小小鱼(xxy) 的小汽车在每轮行进过程中,都会在墓地上留下一条车辙印,一条车辙印可看作以两座墓碑(或原点和一座墓碑)为端点的一条线段。在 小小鱼(xxy) 之后,还有很多许愿者计划驾车来墓地许愿,这些许愿者都会像 小小鱼(xxy) 一样任选一种最优策略行动。hkd认为非左右方向(即上、左上 45° 、右上 45° 三个方向)的车辙印很不美观,为了维护墓地的形象,他打算租用一些挖掘机,在这群许愿者到来之前夯实所有“可能留下非左右方向车辙印”的地面。“可能留下非左右方向车辙印”的地面应当是墓地上的若干条线段,其中每条线段都包含在某一种最优策略的行进路线中。每台挖掘机都采取满足以下三个条件的工作模式:从原点或任意一座墓碑出发。

只能向上、左上 45° 、右上 45° 三个方向之一移动,并且只能在树下改变方向或停止。只能经过“可能留下非左右方向车辙印”的地面,但是同一块地面可以被多台挖掘机经过。

现在 小小鱼(xxy) 和 hkd分别向你提出了一个问题:

请给 小小鱼(xxy) 指出任意一条最优路线。请告诉 hkd最少需要租用多少台挖掘机。

输入格式

输入文件的第 1 行包含 1 个正整数 n,表示墓碑的数量。

接下来 n 行,第 i+1 行包含 2 个整数 xi,yi,中间用单个空格隔开,表示第 i 座墓碑的坐标。

输出格式

输出文件包括 3 行。

输出文件的第 1 行输出 1 个整数 m,表示 小小鱼(xxy) 最多能在多少座墓碑下许愿。

输出文件的第 2 行输出 m 个整数,相邻整数之间用单个空格隔开,表示 小小鱼(xxy) 应该依次在哪些墓碑下许愿。

输出文件的第 3 行输出 1 个整数,表示 hkd最少需要租用多少台挖掘机。

 

样例输入

6
-1       1
1        1
-2       2
0        8
0        9
0        10

样例输出

3
2 1 3
3

 

转载于:https://www.cnblogs.com/z360/p/7521749.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>