Noip2012普及组

T2:

传说很遥远的藏宝楼顶层藏着诱人的宝藏。小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书。说明书的内容如下:

藏宝楼共有N+1层,最上面一层是顶层,顶层有一个房间里面藏着宝藏。除了顶层外,藏宝楼另有N层,每层M个房间,这M个房间围成一圈并按逆时针方向依次编号为0,…,M-1。其中一些房间有通往上一层的楼梯,每层楼的楼梯设计可能不同。每个房间里有一个指示牌,指示牌上有一个数字x,表示从这个房间开始按逆时针方向选择第x个有楼梯的房间(假定该房间的编号为k),从该房间上楼,上楼后到达上一层的k号房间。比如当前房间的指示牌上写着2,则按逆时针方向开始尝试,找到第2个有楼梯的房间,从该房间上楼。如果当前房间本身就有楼梯通向上层,该房间作为第一个有楼梯的房间。

寻宝说明书的最后用红色大号字体写着:“寻宝须知:帮助你找到每层上楼房间的指示牌上的数字(即每层第一个进入的房间内指示牌上的数字)总和为打开宝箱的密钥”。

请帮助小明算出这个打开宝箱的密钥。

输入输出格式

输入格式:

第一行2个整数N和M,之间用一个空格隔开。N表示除了顶层外藏宝楼共N层楼,M表示除顶层外每层楼有M个房间。

接下来N*M行,每行两个整数,之间用一个空格隔开,每行描述一个房间内的情况,其中第(i-1)*M+j行表示第i层j-1号房间的情况(i=1,2,…, N;j=1,2,…,M)。第一个整数表示该房间是否有楼梯通往上一层(0表示没有,1表示有),第二个整数表示指示牌上的数字。注意,从j号房间的楼梯爬到上一层到达的房间一定也是j号房间。

最后一行,一个整数,表示小明从藏宝楼底层的几号房间进入开始寻宝(注:房间编号从0开始)。

输出格式:

输出只有一行,一个整数,表示打开宝箱的密钥,这个数可能会很大,请输出对20123取模的结果即可。

输入输出样例

输入样例#1:

2 3

1 2

0 3

1 4

0 1

1 5

1 2

1

输出样例#1:

5

【数据范围】

对于50%数据,有0<N≤1000,0<x≤10000;

对于100%数据,有0<N≤10000,0<M≤100,0<x≤1,000,000。

这道题目其实就是一道模拟题,其中如果用纯模拟的方法只能得50分,所以可以优化。

判断到达哪个楼梯房间的时候可以用周期的原理,只求取模后的值来模拟即可——这样就可以大大的减少复杂度了。

代码:

var
         bz,num:array[0..10000,0..100] of longint;
         c:array[0..10000] of longint;
         i,j,n,m,w,ans,sum:longint;
begin
         assign(input,'treasure.in'); reset(input);
         assign(output,'treasure.out'); rewrite(output);

         readln(n,m);
         for i:=1 to n do
                  for j:=1 to m do
                  begin
                           readln(bz[i,j],num[i,j]);
                           if bz[i,j]=1 then inc(c[i]);
                  end;
         readln(w);  inc(w);
         for i:=1 to n do
         begin
                  ans:=(ans+num[i,w]) mod 20123;
                  j:=(num[i,w]-1) mod c[i]+1;
                  sum:=bz[i,w];
                  while sum<>j do
                  begin
                           w:=w mod m+1;
                           inc(sum,bz[i,w]);
                  end;
         end;
         writeln(ans);

         close(input);close(output);
end.

当然,其实上面代码的时间复杂度为O(nm),但如果M再大一点的话,即需要O(n)的算法——可以再优化一下,把取模后的值在判断是哪个楼梯的时候可以优化,优化成O(1)的计算,a[i,t]的值就是当前是在哪个楼梯,主要是注意f[i,j]表示的是第i层到第j个房间截止有多少个楼梯房间。f[i,w]+(tot[i,w] mod a[i,0])就是要求的值了。其次还需要注意的是,有可能t的值=0,这时候w就等于第i层最后一个房间。

代码(但实质上对于这道题的数据时间并没有体现多少,如果m大一点的话则必须用此方法):

var
        n,m,i,j,w,ans,t:longint;
        bz:array[1..10000,0..100] of 0..1;
        a,tot,f:array[1..10000,0..100] of Longint;
begin
        assign(input,'treasure.in'); reset(input);
        assign(output,'treasure.out'); rewrite(output);

        readln(n,m);
        for i:=1 to n do
                for j:=1 to m do
                begin
                        readln(bz[i,j],tot[i,j]);
                        f[i,j]:=f[i,j-1];
                        if bz[i,j]=1 then
                        begin
                                inc(a[i,0]);
                                a[i,a[i,0]]:=j;
                                inc(f[i,j]);
                        end;
                end;
        readln(W);
        inc(w);
        for i:=1 to n do
        begin
                ans:=(ans+tot[i,w]) mod 20123;
                if bz[i,w]=1 then dec(tot[i,w]);
                t:=((tot[i,w] mod a[i,0])+f[i,w]-1) mod a[i,0]+1;
                if t<>0 then w:=a[i,t] else w:=a[i,a[i,0]];
        end;
        writeln(ans);

        close(input); close(output);
end.

T2:

小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。

试编程计算,一共有多少种不同的摆花方案。

输入输出格式

输入格式:

第一行包含两个正整数n和m,中间用一个空格隔开。

第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。

输出格式:

输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。

输入输出样例

输入样例#1:

2 4

3 2

输出样例#1:

2

说明

【数据范围】

对于20%数据,有0<n≤8,0<m≤8,0≤ai≤8;

对于50%数据,有0<n≤20,0<m≤20,0≤ai≤20;

对于100%数据,有0<n≤100,0<m≤100,0≤ai≤100。

这道题目就是赤裸裸的DP,状态也很容易想到——设f[i,j]表示摆i种花在前j个位置上的方案数,显然f[i,j]:=f[i,j]+f[i-1,j-k]。边界f[i,0]:=1;

代码:

var
        a:array[1..100] of Longint;
        f:array[0..100,0..100] of Longint;
        n,m,i,j,k:Longint;
function min(x,y:LONgint):Longint;
begin
        if x<y then exit(x) else exit(y);
end;

begin
        assign(input,'flower.in'); reset(input);
        assign(output,'flower.out'); rewrite(output);

        read(n,m);
        for i:=1 to n do
                read(a[i]);
        for i:=0 to n do
                f[i,0]:=1;
        for i:=1 to n do
                for j:=1 to m do
                        for k:=0 to min(j,a[i]) do
                                f[i,j]:=(f[i,j]+f[i-1,j-k]) mod 1000007;
        writeln(f[n,m]);

        close(input); close(output);
end.

T4:

有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一种文化超过一次(即如果他学习了某种文化,则他就不能到达其他有这种文化的国家)。不同的国家可能有相同的文化。不同文化的国家对其他文化的看法不同,有些文化会排斥外来文化(即如果他学习了某种文化,则他不能到达排斥这种文化的其他国家)。现给定各个国家间的地理关系,各个国家的文化,每种文化对其他文化的看法,以及这位使者游历的起点和终点(在起点和终点也会学习当地的文化),国家间的道路距离,试求从起点到终点最少需走多少路。

输入输出格式

输入格式:

第一行为五个整数 N,K,M,S,T,每两个整数之间用一个空格隔开,依次代表国家

个数(国家编号为 1 到 N),文化种数(文化编号为 1 到 K),道路的条数,以及起点和终点的编号(保证 S 不等于 T);

第二行为 N 个整数,每两个整数之间用一个空格隔开,其中第 i 个数 Ci,表示国家 i的文化为 Ci。

接下来的 K 行,每行 K 个整数,每两个整数之间用一个空格隔开,记第 i 行的第 j 个数为 aij,aij= 1 表示文化 i 排斥外来文化 j(i 等于 j 时表示排斥相同文化的外来人),aij= 0 表示不排斥(注意 i 排斥 j 并不保证 j 一定也排斥 i)。

接下来的 M 行,每行三个整数 u,v,d,每两个整数之间用一个空格隔开,表示国家 u与国家 v 有一条距离为 d 的可双向通行的道路(保证 u 不等于 v,两个国家之间可能有多条道路)。

输出格式:输出只有一行,一个整数,表示使者从起点国家到达终点国家最少需要走的距离数(如果无解则输出-1)。

输入输出样例

输入样例#1:

输入输出样例 1

2 2 1 1 2

1 2

0 1

1 0

1 2 10

输入输出样例 2

2 2 1 1 2

1 2

0 1

0 0

1 2 10

输出样例#1:

输入输出样例 1

-1

输入输出样例 2

10

说明

输入输出样例说明1

由于到国家 2 必须要经过国家 1,而国家 2 的文明却排斥国家 1 的文明,所以不可能到达国家 2。输入输出样例说明2路线为 1 -> 2

【数据范围】

对于 100%的数据,有 2≤N≤100 1≤K≤100 1≤M≤N2 1≤ki≤K 1≤u, v≤N 1≤d≤1000 S≠T 1≤S,T≤N

这道题数据非常的坑,又坑又烂,例如,“正确”的dfs倒过来搜就行了,这里正确为什么要打引号?因为题目中有一个规定就是不能学过重复的文化,还有就是每个文化之间都不能排斥,而不仅仅是两两城市之间不排斥,而这两个规定即使不加同样能AC——因为没有了这个两个规定,即这道题用Floyd也可以做对了!——但是这道题的正解我认为是spfa,因为数据如果大一点,强悍一点,Dfs是过不了的,而floyd答案是错误的,只有spfa才能做对,spfa里面需要很多的判重。

例如——dis[i].bz是判断不能学重复的文化,而dis[i].xuan是选中的文化不能排斥。如果没了这两个判重真不知难点在哪里,然而就算有这两个判重好像这也不是难点吧。

spfa算法的方法:

type
        arr=array[0..100] of longint;
var
        c:array[1..100] of longint;
        a:array[1..100,0..1000] of longint;
        bz,d:array[1..100,1..100] of longint;
        data:array[1..1000] of longint;
        f:array[1..100] of boolean;
        dis:array[1..100] of record way:longint; xuan:arr end;
        n,k,m,s,t,i,j,x,y,way,head,tail,w:longint;
function pd(x:arr; k:longint):boolean;
var
        i:LONGINT;
begin
        for i:=1 to x[0] do
                if (bz[c[k],c[x[i]]]=1) then exit(false);
        exit(true);
end;
begin
        assign(input,'culture.in'); reset(input);
        assign(output,'culture.out'); rewrite(output);

        readln(n,k,m,s,t);
        for i:=1 to n do
                read(c[i]);
        for i:=1 to k do
        begin
                for j:=1 to k do
                        read(bz[i,j]);
                readln;
        end;
        fillchar(d,sizeof(d),5);
        for i:=1 to m do
        begin
                read(x,y,way);
                inc(a[x,0]);
                a[x,a[x,0]]:=y;
                if way<d[x,y] then d[x,y]:=way;

                inc(a[y,0]);
                a[y,a[y,0]]:=x;
                if way<d[y,x] then d[y,x]:=way;
        end;

        head:=0;
        tail:=1;
        fillchar(dis,sizeof(dis),5);
        dis[s].way:=0;
        dis[s].xuan[0]:=1;
        dis[s].xuan[1]:=s;
        data[1]:=s;
        while head<tail do
        begin
                inc(head);
                w:=data[head];
                for i:=1 to a[w,0] do
                        if pd(dis[w].xuan,a[w,i]) and (dis[a[w,i]].way>dis[w].way+d[w,a[w,i]]) then
                        begin
                                dis[a[w,i]]:=dis[w];
                                dis[a[w,i]].way:=dis[a[w,i]].way+d[w,a[w,i]];
                                inc(dis[a[w,i]].xuan[0]);
                                dis[a[w,i]].xuan[dis[a[w,i]].xuan[0]]:=a[w,i];
                                if not f[a[w,i]] then
                                begin
                                        f[a[w,i]]:=true;
                                        inc(tail);
                                        data[tail]:=a[w,i];
                                end;
                        end;
                f[w]:=false;
        end;

        if dis[t].way=84215045 then writeln(-1) else writeln(dis[t].way);

        close(input); close(output);
end.
时间: 2024-08-11 07:03:26

Noip2012普及组的相关文章

NOIP2012普及组 (四年后的)解题报告 -SilverN

本章施工仍未完成 现在的时间是3.17 0:28,我困得要死 本来今天(昨天?)晚上的计划是把整个四道题的题解写出来,但是到现在还没写完T4的高效算法,简直悲伤. 尝试了用floyd写T4,终于大功告成AC后,看到别人的解题报告说fl能过只是因为测试数据范围小. 好像主要有三种解法,fl,dij,dfs dfs暂时弃,dij写到现在还没完成,先把fl的放上来. 等攻下T4,再施工前面三道题 T4-Floyd: 读完数据以后,只要把文化不兼容的城市的路都堵上,就可以用floyd了 可怜我之前堵路无

[Noip2012普及组]摆花

Description 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m 盆.通过调查顾客的喜好,小明列出了顾客最喜欢的 n 种花,从 1 到 n 标号.为了在门口展出更多种花,规定第 i 种花不能超过 ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列.试编程计算,一共有多少种不同的摆花方案 Input 共 2 行.第一行包含两个正整数 n 和 m,中间用一个空格隔开.第二行有 n 个整数,每两个整数之间用一个空格隔开,依次表示 a1.a2.--a

noip2012 普及组

T1 质因数分解 题目传送门 #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long using namespace std; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c&g

NOIP2012普及组--质因数分解

分析:一遍遍循环,效率比较低,但可以通过减半和除偶来减少次数,但是依旧不是很理想,数论中有个定论是任意合数都可以由 几个质数乘的,但是目前还没想好怎么运用这个定论,所以将就一下. PS:这个数肯定是合数,因为1不是质数,所以不可能是1和本身. 1 #include <stdio.h> 2 int main() 3 { 4 int n,i; 5 int j,x=0; 6 scanf("%d",&n); 7 for(i=(n/2);i>2;i--) //因为质因数

NOIP2012普及组解题报告

by RtPYH ------------------------------------------------------------------------------------------------------------------ 前言:作者是一个蒟蒻,如果对本文有建议,欢迎提出!鄙人将虚心接受. --------------------------------------------------------------------------------------------

Noip2012 普及组 第三题 摆花

博主声明: 新手第一次写动规的题解,如果出现错误请各位大力的喷,但不要骂脏话,最好告诉我怎么改,谢谢~.~ !!! 摆花 (flower.cpp/c/pas) [问题描述] 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m 盆. 通过调查顾客的喜好,小明列出了顾客最喜欢的 n 种花,从 1 到 n 标号. 为了在门口展出更多种花,规定第 i 种花不能超过 ai 盆, 摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列. 试编程计算,一共有多少种不同的摆花方案

2017年8月14日套题记录 | 普及组

写在前面 今天登洛谷发现离Noip剩下88天了??(虽然看起有点久),然后觉得似乎水了一个暑假什么也没做(虽然学了点数据结构和一些奇奇Gaygay的东西),于是打开题库发现去年Long Happy的集训套题我似乎没有提交过,那就一天一套题,顺便码个题解+心得(雾? T2.传作业 题目描述 某十三同学一日上学迟到,此时已经开始上早自习了,所以他只好请同学帮忙把作业传到组长那里.由于刚开学不久,某十三同学还没来得及认识所有同学,所以传作业时只好找熟悉的同学.已知某十三与组长之间有N个他熟悉的同学,并

1143 纪念品分组 2007年NOIP全国联赛普及组

1143 纪念品分组 2007年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 查看运行结果 题目描述 Description 元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作.为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数.为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少. 你的任务是写一个程序

采药 2005年NOIP全国联赛普及组&amp;疯狂的采药

时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:"孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值.我会给你一段时间,在这段时间里,你可以采到一些草药.如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大."