• NOIP2018 模拟 9.11


    ISIJ 2018 很多序列(Training Round D4T3)


    题目名称:很多序列

    文件名:sequences.in / sequences.out

    题目描述

    假设 $ x_1 < x_2 < dots < x_n $ 且 $ x_1 $ 与 $ x_2 $ 互质。
    考虑所有的单调递增序列,其首项为 $ 0 $ 且相邻两项之差是 $ x_1,x_2 dots x_n $ 之一。
    例如,当 $ n=2, x_1 = 4 , x_2 = 7 $ 时,序列可以是 $ 0, 4, 8, 15, 19, 26, 33, 40, 44 $ 。
    那么请问不出现在任何序列中最大的数是多少?
     

    限制

    $ 1s quad 256M $

    对于 40% 的数据,$ 1 < n < 6 , x_1 > 1 , x_n <1000 $ ;
    对于另外 30% 的数据,$ n=2 , x_n < 10^ 9 $ ;
    对于另外 30% 的数据,$ 1 < n < 6 , 1 < x_1 < 10^{6-n} , x_2 > 10^{n+11} , x_n < 10^{n+12} $ 。
     

    输入格式

    第一行,一个整数 $ n $

    第二行,一共 $ n $ 个整数 $ x_1 , x_2 dots x_n $
     

    输出格式

    一个整数,表示不出现在任何序列中最大的数
     

    输入样例

     2
     4 7
    

    输出样例

     17 
    

     

    题解

    $ x_1 < 10^6 $ 按照对 $ x_1 $ 取模建图,从每个点 $ u $ 按边权为 $ x_i $ 向 $ (u+x_i) quad mod quad x_1 $ 连边,
    从 $ 0 $ 出发到 $ u $ 的最短路径长表示,序列中最小的 $ mod quad x_1 = u $ 的数是多少。
    当然,这个数(跑 $ SPFA $ 求最短路) - $ x_1 $ 即为最大的不可取到的数。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define int long long
    #define N 1000005
    int n,x[10],ans;
    void read(int &x){
    	char ch;x=0;
    	while(ch=getchar(),ch<'0'||ch>'9');x=ch-48;
    	while(ch=getchar(),ch>='0'&&ch<='9')x=10*x+ch-48;
    }
    queue<int>q;
    int dis[N];
    bool vis[N];
    inline void spfa(){
    	memset(dis,0x6f,sizeof(dis));
    	q.push(0); dis[0]=0; 
    	while(!q.empty()){
    		int u=q.front(); q.pop(); vis[u]=0;
    		for(int i=2;i<=n;++i){
    			int v=(u+x[i]%x[1])%x[1];
    			if(dis[v]>dis[u]+x[i]){
    				dis[v]=dis[u]+x[i];
    				if(!vis[v]){ vis[v]=1; q.push(v); }
    			}
    		}
    	}
    }
    signed main(){
    	freopen("sequence.in","r",stdin);
    	freopen("sequence.out","w",stdout);
    	read(n);
    	for(int i=1;i<=n;++i) read(x[i]);
    	if(n==2) printf("%lld",x[1]*x[2]-x[1]-x[2]);
    	else {
    		spfa();
    		for(int i=1;i<x[1];++i) ans=max(ans,dis[i]);
    		printf("%lld",ans-x[1]);
    	}
    	return 0;
    }
    

     
     

    ISIJ 2018 移动光标(Cup T2)


    题目名称:移动光标

    文件名:cusor.in / cusor.out

    题目描述

    小明是一名优秀的打字员,他正在检查一份文本文件,现在已知第 $ i ( 1 le i le n ) $ 行有 $ L_i $ 个字符。
    每时每刻光标会指向一个字符,小明可以通过键盘上的 4 个键移动光标位置。
    按下 “ ↑ ” 时,光标会直接移动到上一行对应的字符处,如果已经在第一行或上一行没有同列的字符,则不作移动。
    按下 “ ↓ ” 时,光标会直接移动到下一行对应的字符处,如果已经在第 行或下一行没有同列的字符,则不作移动。
    按下 “ ← ” 时,光标会直接移动到同行左边的字符处,如果左边已没有字符,则不作移动。
    按下 “ → ” 时,光标会直接移动到同行右边的字符处,如果右边已没有字符,则不作移动。
    现在小明有 $ q $ 次询问 $ x_1 , y_1 , x_2 ,y_2 $ 表示光标需要从第 $ x_1 $ 行第 $ y_1 $ 个字符移动到第 $ x_2 $ 行第 $ y_2 $ 个字符,
    求出 最少按几次键盘(保证 $ 1 le y_1 le L_{x_1}, 1 le y_2 le L_{x_2} $ )。
     

    限制

    $ 2s quad 256M $

    $ 1 le n, L_i ,q le 10^5 $

    输入格式

    第一行,一个整数 $ n $
    接下来 $ n $ 行,其中第 $ i $ 行一个整数 $ L_i $
    接下来一行,一个整数 $ q $
    接下来 $ q $ 行,每行 4 个整数 $ x_1 , y_1 , x_2 , y_2 $
     

    输出格式

    一共 $ q $ 行,每行表示对应询问的答案
     

    输入样例

     4 
     3
     2
     4
     3
     3
     1 1 3 2
     3 3 4 2
     1 3 3 4 
    
    

    输出样例

     3
     2
     5 
    

     

    题解

    大致路径是先横再往上/下再横着走,
    如果 $ x_1 $ 到 $ x_2 $ 之间的 $ L $ 最小值(线段树维护区间最小值)$ m $ 比 $ y_1 $ 和 $ y+2 $ 都 小,
    那么需要额外从 $ y_1 $ 走到 $ m $ 并从 $ m $ 走到 $ y_2 $ ;其他情况都是 $ |x_1-x_2| + | y_1-y_2| $ 。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,q,sum[100005<<2],x1,x2,y1,y2;
    void read(int &x){
    	char ch;x=0;
    	while(ch=getchar(),ch<'0'||ch>'9');x=ch-48;
    	while(ch=getchar(),ch>='0'&&ch<='9')x=10*x+ch-48;
    }
    void build(int o,int l,int r){
    	if(l==r){
    		read(sum[o]);
    		return;
    	}
    	int mid=l+r>>1;
    	build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    	sum[o]=min(sum[o<<1],sum[o<<1|1]);
    }
    int query(int o,int l,int r,int L,int R){
    	if(L<=l&&r<=R) return sum[o];
    	int mid=l+r>>1;
    	if(L>mid) return query(o<<1|1,mid+1,r,L,R);
    	else if(R<=mid) return query(o<<1,l,mid,L,R);
    	else return min(query(o<<1,l,mid,L,R),query(o<<1|1,mid+1,r,L,R));
    }
    int main(){
    	freopen("cusor.in","r",stdin);
    	freopen("cusor.out","w",stdout);
    	read(n);
    	build(1,1,n);
    	read(q);
    	while(q--){
    		read(x1); read(y1); read(x2); read(y2);
    		int tmp=query(1,1,n,min(x1,x2),max(x1,x2));
    		if(y1<=tmp&&y2<=tmp) printf("%d
    ",abs(x2-x1)+abs(y2-y1));
    		else printf("%d
    ",abs(y1-tmp)+abs(y2-tmp)+abs(x2-x1));
    	}
    	return 0;
    }
    

     

     

    ISIJ 2018 假期旅行(Training Round D6T2)

    题目描述

    这个假期,小明打算乘火车游览风光,沿途一共经过 $ n $ 个城市。
    从第 $ i $ 个城市设有第 $ i $ 条铁路到达第 $ i+1 $ 个城市,这连成一条铁路链。
    小明乘坐的这班火车一共有 $ k $ 个座位,从第 $ 1 $ 个城市开到第 $ n $ 个城市,但在买票时遇到 了困难,因为火车上的部分座位被订掉了。
    有 $ m $ 位乘客的订单可以用各自的 $ (s,t,a) $ 来描述,
    表示从第 $ s $ 个城市坐车到第 $ t $ 个城市,订了这段中的第 $ a $ 个座位(不保证乘客之间是否存在冲突,但这不会影响到小明)。
     
    小明沮丧地发现可能没有座位从头到尾都没人预订的,不过他马上意识到自己可以订不同的座位,
    只需要保证第 $ i $ 条铁路中坐的座位是没人预订的。
    小明会一共乘坐 $ q $ 次火车,从第 $ l $ 到第 $ r $ 个城市。
    你需要求出期间最少换几个座位(第 $ i $ 和第 $ i+1 $ 条铁路中座位不同的个数),如果无法从 $ l $ 抵达 $ r $ 则输出 $ -1 $ 。
     

    限制

    $ 2s quad 256M $
    对于 30% 的数据,$ nle 100 , m le 100 , kle 100 , q=1 $
    对于 60% 的数据,$ n le 200,000 , mle 200,000 , k le 200,000, q=1 $
    对于 100% 的数据,$ 1le n le 200,000 ,0 le m le 200,000 , 1 le k le 200,000 , 1 le q le 200,000 $
     

    输入格式

    第一行,$ 3 $ 个整数 $ n,m $ 和 $ k $
    接下来 $ m $ 行,每行 3 个正整数表示这个乘客的 $ s, t $ 和 $ a ( 1 le s < t le n , 1 le a le k ) $
    接下来一行,$ 1 $ 个正整数 $ q $
    接下来 $ q $ 行,每行 $ 2 $ 个正整数 $ l $ 和 $ r ( 1 le l < r le n) $
     

    输出格式

    一共 $ q $ 行,每行一个整数表示最少要换几次座位,若无法到达则输出 $ -1 $
     

    输入样例

     5 4 3
     1 4 1
     2 5 3
     2 3 2
     4 5 2 
     3
     1 5
     3 5
     4 5
    

    输出样例

     -1
     2
     1
    

     

    样例解释

    第 $ 2 $ 条轨道上所有座位都被预订了,因此从第 $ 1 $ 到第 $ 5 $ 个城市是不可能的。
    从第 $ 3 $ 到第 $ 5 $ 个城市可以先买座位 $ 2 $ 的票、再换到座位 $ 1 $ 。
    从第 $ 4 $ 到第 $ 5 $ 个城市只需要买座位 $ 1 $ 的票即可。
     

    题解

    对于每个城市 $ i $ ,记录 $ a[i] $ 表示 $ i $ 向后最远可以只用一种车票走到哪里。
    先将 $ m $ 个订单离线,处理同个座位的预订区间(若有相交的区间则合并,可以扫描线处理区间),
    相邻两个区间之间的部分是可以使用这种车票的,用线段树(维护最大值)更新这段的 $ a[i] $ 为右端点(即原来的下一个区间左端点)。
    由 $ i $ 指向 $ a[i] $ 即构成了森林(因为 $ i le a[i] $ ),求从 $ l $ 到 $ r $ 的路径长度时使用倍增即可。
    预处理 $ O (n imes log_n $ ,询问在线每次 $ O(log_n) $ 。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define N 200005
    vector<pair<int,int> >val[N];
    void read(int &x){
    	char ch;x=0;
    	while(ch=getchar(),ch<'0'||ch>'9');x=ch-48;
    	while(ch=getchar(),ch>='0'&&ch<='9')x=10*x+ch-48;
    }
    int sum[N<<2],lzy[N<<2];
    inline void pushdown(int o){
    	sum[o<<1]=max(sum[o<<1],lzy[o]);
    	sum[o<<1|1]=max(sum[o<<1|1],lzy[o]);
    	lzy[o<<1]=max(lzy[o<<1],lzy[o]);
    	lzy[o<<1|1]=max(lzy[o<<1|1],lzy[o]);
    	lzy[o]=0;
    }
    void modify(int o,int l,int r,int L,int R,int v){
    	if(L<=l&&r<=R){
    		sum[o]=max(sum[o],v);
    		lzy[o]=max(lzy[o],v);
    		return;
    	}
    	if(lzy[o]) pushdown(o);
    	int mid=l+r>>1;
    	if(L>mid) modify(o<<1|1,mid+1,r,L,R,v);
    	else if(R<=mid) modify(o<<1,l,mid,L,R,v);
    	else {
    		modify(o<<1,l,mid,L,R,v);
    		modify(o<<1|1,mid+1,r,L,R,v);
    	}
    	sum[o]=max(sum[o<<1],sum[o<<1|1]);
    }
    int query(int o,int l,int r,int x){
    	if(l==r) return sum[o];
    	if(lzy[o]) pushdown(o);
    	int mid=l+r>>1;
    	if(x>mid) return query(o<<1|1,mid+1,r,x);
    	else return query(o<<1,l,mid,x);
    	sum[o]=max(sum[o<<1],sum[o<<1|1]);
    }
    int f[N][21],n,m,k,ans,q;
    int main(){
    	freopen("trip.in","r",stdin);
    	freopen("trip.out","w",stdout);
    	read(n); read(m); read(k);
    	for(int i=1;i<=m;++i){
    		int s,t,a;
    		read(s); read(t); read(a);
    		val[a].push_back(make_pair(s,t-1));
    	}
    	for(int i=1;i<=k;++i){
    		sort(val[i].begin(),val[i].end());
    		int L=0,R=-1;
    		for(int j=0;j<val[i].size();++j)
    			if(val[i][j].first<=R+1) R=max(R,val[i][j].second);
    			else{
    				modify(1,0,n,R+1,val[i][j].first-1,val[i][j].first);
    				L=val[i][j].first; R=val[i][j].second;
    			}
    		modify(1,0,n,R+1,n,n);
    	}
    	for(int i=1;i<n;++i){
    		int tmp=query(1,0,n,i);
    		if(!tmp) tmp=n+1;
    		f[i][0]=tmp;
    	}
    	f[n][0]=n; f[n+1][0]=n+1;
    	for(int j=1;j<=20;++j)
    		for(int i=n+1;i>=1;--i)
    			f[i][j]=f[f[i][j-1]][j-1];
    	read(q);
    	while(q--){
    		int l,r; ans=0;
    		read(l); read(r);
    		for(int i=20;~i;--i) if(f[l][i]<r){ l=f[l][i]; ans+=(1<<i); }
    		l=f[l][0]; ++ans;
    		if(l==n+1||l<r) puts("-1");
    		else printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    修改计算机名并更新sqlserver中存储的服务器名称
    SqlServer递归查询
    CSS实现文本溢出显示省略号
    浏览器缓存
    闭包(匿名函数) php
    github添加ssh认证
    hive内置方法一览
    Redis went away
    慢查询日志分析(mysql)
    慢查询日志(mysql)
  • 原文地址:https://www.cnblogs.com/PotremZ/p/Test20180925.html
Copyright © 2020-2023  润新知