【比赛报告】洛谷线上赛NOIP2018原创模拟赛DAY1 NOIP练习赛卷一

比赛传送门
题解传送门
2018.9.23 2 14 40 100 + 100 + 60 = 260 自测时间:2018.9.23\quad用时:2小时14分40秒\quad得分:100+100+60=260

T1 U32670 小凯的数字

题目背景

NOIP2018 原创模拟题T1

NOIP DAY1 T1 or DAY 2 T1 难度

是否发现与NOIP2017 DAY1 T1 有异曲同工之妙

说明:#10,bug已修复

题目描述

小凯有一天突发奇想,写下了一串数字: l ( l + 1 ) ( l + 2 ) . . . ( r 1 ) r l ( l + 1 ) ( l + 2 ) . . . ( r 1 ) r l(l+1)(l+2)...(r-1)rl(l+1)(l+2)...(r−1)r
例如: l = 2 , r = 5 l=2,r=5 时,数字为: 2345 2345
l = 8 , r = 12 l=8,r=12 时数字为: 89101112 89101112
小凯很喜欢数字9,所以他想问你他写下的数字除以9的余数是多少

例如: l = 2 , r = 5 l=2,r=5 时, 2345 m o d    9 = 5 2345 \mod 9 = 5

输入输出格式

输入格式:

第一行为数字 Q Q ,表示小凯有 Q Q 个问题

2 ,   , Q + 1 2,\cdots,Q+1 行,每行两个数字 l,r 表示数字范围

输出格式:

对于每行的问题输出一行,一个数字,表示小凯问题的回答

输入输出样例

输入样例#1:

2
2 5
8 12

输出样例#1:

5
5

输入样例#2:

3
1 999
123 456
13579 24680

输出样例#2:

0
6
0

说明

样例1解释: 2345 m o d    9 = 5 2345 \mod 9 = 5 89101112 m o d    9 = 5 89101112 \mod 9 = 5

30 % 30\% 数据满足: Q 10 ; l , r 100 Q\le 10;l,r\le100
50 % 50\% 数据满足: Q 100 ; l , r 10000 Q\le100;l,r\le10000
70 % 70\% 数据满足: Q 1000 ; l , r 1 0 6 Q\le1000;l,r\le10^6
100 % 100\% 数据满足: Q 10000 ; l , 0 < r 1 0 12 Q 10000 ; l r Q\le10000;l,0<r\le10^{12}Q\le10000;且 l\le r


我的方法和题解的不一样。
记这个自然数为 l ( l + 1 ) ( l + 2 ) ( r 1 ) r \overline{l(l+1)(l+2)\cdots(r-1)r}
显然答案可以变形为 ( l × 1 0 r l m o d    9 + ( l + 1 ) ( l + 2 ) ( r 1 ) ( r ) m o d    9 ) m o d    9 (l\times 10^{r-l}\mod 9+\overline{(l+1)(l+2)\cdots(r-1)(r)}\mod 9)\mod 9
l × 1 0 r l m o d    9 = ( l m o d    9 ) × ( 1 0 r l m o d    9 ) m o d    9 l\times 10^{r-l}\mod 9=(l\mod9)\times(10^{r-l}\mod9)\mod9
1 0 r l m o d    9 = 1 10^{r-l}\mod9=1 ,即原式 = l m o d    9 =l\mod9
以此类推,答案可以写做 i = l r i m o d    9 \sum_{i=l}^ri\mod9
题解到此处就套用求和公式得解,详见NOIP2018原创模拟赛DAY1题解,而我比赛时尝试前缀和思想求解(其实是没反应过来有个求和公式来着)。
显然, i = 1 9 i m o d    9 = 0 \sum_{i=1}^9i\mod9=0 ,可将答案变形为 ( s u m [ r m o d    9 ] s u m [ ( l 1 + 9 ) m o d    9 ] + 9 ) m o d    9 \Big(sum[r\mod9]-sum[(l-1+9)\mod9]+9\Big)\mod9 ,其中 s u m sum 为0~8的前缀和。
绕了一圈此题得解,妈妈再也不用担心我爆 l o n g l o n g long long 了。

#include<cstdio>
typedef long long ll;
int q,sum[9];
ll l,r;
int main()
{
	//freopen("in.txt","r",stdin);
	scanf("%d",&q);
	for(int i=1;i<9;i++)sum[i]=(sum[i-1]+i)%9;
	while(q--)
	{
		scanf("%lld%lld",&l,&r);
		printf("%d\n",(sum[r%9]-sum[(l%9-1+9)%9]+9)%9);
	}
	return 0;
}

总结

此题作为T1,确实是送分的,参加比赛的人大多拿满了,没啥可说的。


T2 U38181 密室

题目背景

NOIP2018 原创模拟题 T2

NOIP DAY1 T2 or DAY2 T2 难度

题目背景改编自小说《哈利波特与密室》。

说明:#4,bug经修复,感谢:@唐子川

题目描述

密室被打开了。
哈利与罗恩进入了密室,他们发现密室由n个小室组成,所有小室编号分别为:1,2,…,n。所有小室之间有m条通道,对任意两个不同小室最多只有一条通道连接,而每通过一条通道都需要Ci 的时间。

开始时哈利与罗恩都在编号为1的小室里,他们的目标是拯救金妮和寻找日记,但是他们发现金妮和日记可能在两个不同的小室里,为了尽快发现真相,他们决定以最少的时间到达两个目标小室。但是某些小室只有会与蛇对话的人才能进入,也就是只有哈利一个人可以进入。

现在,哈利告诉你密室的结构,请你计算他们到达两个目标小室的最短时间。

输入输出格式

输入格式:

第一行 n , m , k n,m,k 表示有 n n 个小室 m m 条通道, k k 间小室只有哈利可以进入。

第二行 k k 个数,表示只有哈利可以进入的小室的编号。(若 k = 0 k=0 ,不包含该行)

接下来 m m 行,每行 3 3 个数: a , b , c a,b,c 表示 a a 小室与 b b 小室之间有一条需要花费 c c 时间的通道。

最后一行,两个数 x , y x,y 表示哈利与罗恩需要去的小室的编号

输出格式:

一行,输出一个数,表示到达两个密室的最短时间。

输入输出样例

输入样例#1:

6 8 1
5
1 2 3
2 3 2
1 3 4
3 4 1
4 6 5
5 6 2
1 6 6
1 5 3
4 6

输出样例#1:

5

输入样例#2:

10 13 3
3 4 10
1 2 1
2 3 2
3 4 3
4 5 4
5 6 5
6 7 10
7 8 5
8 9 10
9 10 3
10 1 2
1 9 6
3 8 10
4 6 3
6 8

输出样例#2:

16

说明

样例解释:

样例一:

哈利: 1 5 6 1\to5\to6 花费时间为 5 5

罗恩: 1 3 4 1\to3\to4 花费时间为 5 5

所以最短时间为 5 5

样例二:

图1

如图,橙色表示目标小室,绿色只有哈利可以通过

哈利: 1 2 3 4 6 1\to2\to3\to4\to6 花费时间为 9 9

罗恩: 1 9 8 1\to9\to8 花费时间为 16 16

所以最短时间为 16 16

数据范围:

10 % 10\% 数据满足: n 5 n\le5

30 % 30\% 数据满足: n 20 n\le20

50 % 50\% 数据满足: n 1000 n\le1000

70 % 70\% 数据满足: n 10000 n\le10000

100 % 100\% 数据满足: n 50000 a , b , k n c 1000 m 100000 n\le50000 \quad a,b,k\le n \quad c\le1000 \quad m\le100000 ,保证罗恩可以在密室 1 1

特殊约定:

30 % 30\% 数据满足: k = 0 k=0


建立一张完整的图和一张残图,分别跑两遍dijkstra,求出哈利到 x , y x,y 的最短路 d i s [ 1 ] [ x ] , d i s [ 1 ] [ y ] dis[1][x],dis[1][y] 以及罗恩到 x , y x,y 的最短路 d i s [ 2 ] [ x ] , d i s [ 2 ] [ y ] dis[2][x],dis[2][y] 。然后在全图上以 x x 为起点跑一遍dijkstra,求出到y的最短路d[y]。
所求即为:
min ( max ( d i s [ 1 ] [ x ] , d i s [ 2 ] [ y ] ) , max ( d i s [ 2 ] [ x ] , d i s [ 1 ] [ y ] ) , m i n ( d i s [ 1 ] [ x ] , d i s [ 1 ] [ y ] ) + d [ y ] ) \min\Big(\max(dis[1][x],dis[2][y]),\max(dis[2][x],dis[1][y]),min(dis[1][x],dis[1][y])+d[y]\Big)
时间复杂度 O ( ) O(算不来)

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=5e4+10;
const int M=1e5+10;
const int INF=2e9;
int n,m,k,hd[3][N],tot[3],dis[3][N],x,y,d[N],vis[N];
bool ban[N];
struct Edge{
    int v,w,nx;
}e[3][M<<1];
struct Node{
    int to,w;
    Node(){}
    Node(int _to,int _w):to(_to),w(_w){}
    bool operator <(const Node&rhs)const{
    return w>rhs.w;}
};
void add(int id,int u,int v,int w)
{
    e[id][tot[id]].v=v;
    e[id][tot[id]].w=w;
    e[id][tot[id]].nx=hd[id][u];
    hd[id][u]=tot[id]++;
}
void dijkstra(int id)
{
    fill(dis[id],dis[id]+N,INF);
    memset(vis,0,sizeof(vis));
	priority_queue<Node>q;while(q.size())q.pop();
    q.push(Node(1,0));dis[id][1]=0;
    while(q.size())
    {
        Node tmp=q.top();q.pop();
        int u=tmp.to;
        vis[u]=1;
        for(int i=hd[id][u];~i;i=e[id][i].nx)
        {
            int v=e[id][i].v,w=e[id][i].w;
            if(dis[id][v]>dis[id][u]+w)
            {
                dis[id][v]=dis[id][u]+w;
                if(!vis[v])q.push(Node(v,dis[id][v]));
			}
        }
    }
}
void Dijkstra()
{
    fill(d,d+N,INF);
    memset(vis,0,sizeof(vis));
    priority_queue<Node>q;while(q.size())q.pop();
    q.push(Node(x,0)),d[x]=0;
    while(q.size())
    {
        Node tmp=q.top();q.pop();
        int u=tmp.to;vis[u]=1;
        for(int i=hd[1][u];~i;i=e[1][i].nx)
        {
            int v=e[1][i].v,w=e[1][i].w;
            if(d[v]>d[u]+w)
            {
                d[v]=d[u]+w;
                if(!vis[v])q.push(Node(v,d[v]));
            }
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    memset(hd,-1,sizeof(hd));
    scanf("%d%d%d",&n,&m,&k);
    int u,v,w;
    for(int i=1;i<=k;i++)scanf("%d",&u),ban[u]=true;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(1,u,v,w);add(1,v,u,w);
        if(ban[u]||ban[v])continue;
        add(2,u,v,w);add(2,v,u,w);
    }
    scanf("%d%d",&x,&y);
    dijkstra(1);dijkstra(2);
    int ans=min(max(dis[1][x],dis[2][y]),max(dis[2][x],dis[1][y]));
    Dijkstra();
    ans=min(ans,min(dis[1][x],dis[1][y])+d[y]);
    printf("%d\n",ans);
    return 0;
}

总结

实际还是一个最短路问题,建不建两个图都无所谓(题解就没有建双份),然后就是一个分类讨论,很简单,对比NOIP2017DAY1T2……


T3 U38098 PION贪吃蛇

此题我没有发题解出来,因为挂了。其实就是一个大模拟,我是采用双端队列来模拟那条蛇,但是只有六十分……感觉方法没错,先放着吧,代码详见原题解。


赛后总结

T1手推结论正确,并且不用担心爆 l o n g l o n g longlong 的问题。T2之前没有仔细考虑分类讨论的问题,最初的算法是很容易举出反例的但我一开始没有去做。比赛时会因为这种错误丢失不少分数,很不应该,今后比赛时要尽量去证明自己算法的正确性。T3是个大模拟很奇怪,60分也还行吧,过几天再去调试。没有对拍,没有构造数据,做完就交一次,模拟赛期间的第一套模拟题。

猜你喜欢

转载自blog.csdn.net/qq_41958841/article/details/82824595