zoukankan      html  css  js  c++  java
  • NOIP2018 提高组B组模拟 9.22

    【jzoj 1207】遥控车 (Standard IO)

    Time Limits: 1000 ms $ quad $ Memory Limits: 65536 KB Detailed Limits

    Description

    平平带着韵韵来到了游乐园,看到了 $ n $ 辆漂亮的遥控车,每辆车上都有一个唯一的名字 $ name[i] $ 。
    韵韵早就迫不及待地想玩名字是 $ s $ 的遥控车。
    可是韵韵毕竟还小,她想象的名字可能是一辆车名字的前缀
    (也就是说能确定一个 $ i $,使 $ s $ 是 $ name[i] $ 的前缀),
    这时她就能玩第 $ i $ 辆车;或者是一个无中生有的名字,即 $ s $ 不是任何一辆车名字的前缀,这时候她什么也不能玩。
    你需要完成下面的任务:
    1.韵韵想了 $ m $ 个她想要的名字,请告诉她能玩多少次。
    2.由于管理员粗心的操作,导致每辆车的摆放位置都可能出现微小的差错,
    原来第 $ i $ 辆车现在的位置可能是 $ i-1 、i、i+1 $ 中的任意一个
    (第 $ 1 $ 辆车的位置不可能是 $ 0 $ ,第 $ n $ 辆车的位置不可能是 $ n+1 $ )。
    请你计算出共有多少种可能的排列。
    注:数据保证当 $ s $ 是 $ name[i] $ 的前缀时,$ i $ 是唯一确定的。一辆车可以玩多次。
     

    Input

    第一行是 $ 2 $ 个正整数 $ n、m $ 。
    接下来 $ n $ 行,每行 $ 1 $ 个字符串 $ name[i] $,表示第 $ i $ 辆车的名字。
    接下来 $ m $ 行,每行 $ 1 $ 个字符串 $ s $ ,表示韵韵想要的名字。
     

    Output

    第一行输出韵韵能玩的次数。
    第二行输出共有多少种可能的排列。
     

    Sample Input

     4 4  
     Abcd 
     DeF 
     AAa 
     aBccc 
     Ab 
     AA 
     AbC 
     aBcc
    

    Sample Output

     3 
     5 
    

    Data Constraint

    【数据规模和约定】
    对于题目涉及到的字符串严格区分大小写,且长度小于 $ 255 $ 。
    对于 $ 20 $%的数据 $ n≤10,m≤10 $ ;
    对于 $ 40 $%的数据 $ n≤1000,m≤1000 $ ;
    对于 $ 100 $ %的数据 $ n≤10000,m≤10000 $
     

    Solution

    【题意简述】
    本题2问。

    1. 给出 $ N+M $ 个字符串,问后 $ M $ 个字符串中有多少是前 $ N $ 个字符串中某个的前缀。
    2. 数字 $ 1~N $ ,对于 $ i $ 可以放在 $ i-1,i,i+1 $ 中的一个位置上。问有多少种放法。

    【解决方法】
    第一问,我们看到数据规模:$ N、M $ 为 $ 10000 $ 以内的整数,简单模拟逐个去匹配显然是会超时的。
    我们只需要将 $ N $ 个名字串进行一次快速排序,再利用二分查找来检索便可。
    第二问,这一问其实是找递推关系。如果用搜索来做的话是会超时的,因为答案的值是以指数增长的。
    记 $ f(i) $ 为长度为的可能组合数。
    显然,$ f(1)=1;f(2)=2 $ 。
    如果搜索出小数据的答案,就能发现递推关系 $ f(n)=f(n-1)+f(n-2) $ 。
    事实上,假设我们已经求出 $ f(1)~f(i-1) $ 的值。显而易见的,此时第 $ i $ 位仅能放在第 $ i-1 $ 或第 $ i $ 位。
    1.如果第 $ i $ 个数放在第 $ i $ 位,那么此时答案为 $ f(i-1) $ ;
    2.如果第 $ i $ 个数在第 $ i-1 $ 位上,那么第 $ i-1 $ 个数只能放在第 $ i $ 位
    (否则第 $ i $ 位放的是第 $ 1~i-2 $个数,与题意不符),此时答案为 $ f(i-2) $。
    所以当 $ n≥3 $ 时 $ f(n)=f(n-1)+f(n-2) $ 。
    另外,由于答案巨大,需要高精度加法 ,这里不再赘言。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 10005
    int read(){
    	char ch; int x=0;
    	while(ch=getchar(),ch<'0'||ch>'9');x=ch-48;
    	while(ch=getchar(),ch>='0'&&ch<='9')x=10*x+ch-48;
    	return x;
    }
    struct Num{
    	int len,a[100005];
    	void print(){
    		for(int i=len-1;~i;--i) printf("%d",a[i]);
    		puts("");
    	}
    }f1,f2,F;
    string s[N],p;
    int n,m,ans;
    int main(){
    	n=read(); m=read();
    	for(int i=1;i<=n;++i) cin>>s[i];
    	sort(s+1,s+1+n);
    	for(int i=1;i<=m;++i){
    		cin>>p;
    		int l=1,r=n;
    		while(l<=r){
    			int mid=l+r>>1;
    			if(s[mid]<p) l=mid+1; 
    			else r=mid-1;
    		}
    		if(s[l].find(p,0)==0) ++ans;
    	}
    	printf("%d
    ",ans);
    	if(n<=2) printf("%d",n);
    	else {
    		f1.len=1; f1.a[0]=1; 
    		f2.len=1; f2.a[0]=2;
    		for(int i=3;i<=n;++i){
    			F.len=max(f1.len,f2.len);
    			memset(F.a,0,sizeof(F.a));
    			for(int j=0;j<F.len;++j){
    				F.a[j]+=f1.a[j]+f2.a[j];
    				if(F.a[j]>9){
    					F.a[j]%=10;
    					++F.a[j+1];
    				}
    			}
    			if(F.a[F.len]) ++F.len; 
    			f1.len=f2.len; for(int j=0;j<f2.len;++j) f1.a[j]=f2.a[j];
    			f2.len=F.len; for(int j=0;j<F.len;++j) f2.a[j]=F.a[j];
    		}
    		F.print(); 
    	}
    	return 0;
    }
    

    --

    【jzoj 1208】车展 (Standard IO)

    Time Limits: 1000 ms $ quad $ Memory Limits: 65536 KB Detailed Limits

    Description

    遥控车是在是太漂亮了,韵韵的好朋友都想来参观,所以游乐园决定举办 $ m $ 次车展。
    车库里共有 $ n $ 辆 车,从左到右依次编号为 $ 1,2,…,n $ ,每辆车都有一个展台。
    刚开始每个展台都有一个唯一的高度 $ h[i] $ 。主管已经列好一张单子:
    $ L_1 R_1 $
    $ L_2 R_2 $

    $ L_m R_m $
    单子上的 $ (L_i,R_i) $ 表示第 $ i $ 次车展将要展出编号从 $ L_i $ 到 $ R_i $ 的车。
    为了更加美观,展览时需要调整展台的高度,使参展所有展台的高度相等。
    展台的高度增加或减少 $ 1 $ 都 需花费 $ 1 $ 秒时间。由于管理员只有一个人,所以只好对每个展台依次操作。
    每次展览结束后,展台高度 自动恢复到初始高度。
    请告诉管理员为了举办所有展览,他最少需要花多少时间将展台调整好。
     

    Input

    第一行为两个正整数 $ n、m $ 。
    第二行共 $ n $ 个非负整数,表示第 $ i $ 辆车展台的高度 $ h[i] $ 。
    接下来 $ m $ 行每行 $ 2 $ 个整数 $ L_i、R_i(L_i≤R_i)$ 。
     

    Output

    一个正整数,调整展台总用时的最小值。
     

    Sample Input

     6 4 
     4 1 2 13 0 9 
     1 5 
     2 6 
     3 4 
     2 2
    

    Sample Output

     48 
    

     

    Data Constraint

    【数据规模和约定】
    对于 $ 50 $ %的数据 $ n≤500,m≤1000 $;
    对于 $ 80 $ %的数据 $ n≤1000,m≤100000 $ ;
    对于 $ 100 $ %的数据 $ n≤1000,m≤200000 $ ;
    答案小于 $ 2^64 $ 。
     

    Solution

    将所有h[i]对应于数轴上,问题转化为找一个点,使所有的点到这个点的距离和最小。
    至此,很多人已经发现中位数所对应的点可以取到最小值(具体的证明在这里不再详述,很多书籍上都可以找到),
    因此所有展台的高度应为区间[l,r]中的中位数。
    因为要求最小的代价,所以还需要知道区间[l,r]所有数的和,以及小于中位数的所有数的和。
    求中位数的方法有很多,下面介绍几种方法。

    • 方法一:
      对区间 $ [l,r] $ 排序,然后线性扫描得到答案。
      复杂度:$ O(MNlogN) $
      期望得分:50

    • 方法二:
      将所有的高度排序,记录展台的编号。线性扫描后同样可以得到答案
      复杂度:$ O(NlogN+MN) $
      期望得分:70~80

    • 方法三:
      先预处理出每个区间的答案,读入后直接输出。
      这时,需要维护一个大根堆和一个小根堆,其中小根堆中每个数都不小于大根堆中的最大值。
      枚举区间的起点,依次向后加入数,只需控制大根堆中数的个数小于等于小根堆的个数。
      那么大根堆中最大的数就是中位数,大根堆中所有数的和就是小于中位数的所有数的和。具体实现请看标程。
      复杂度:$ O(N2logN+M) $
      期望得分:100

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    const long long N=1010;
    vector<long long> vec[N];
    long long n,m,a[N],ans;
    int main(){
    	scanf("%lld%lld",&n,&m);
    	for(long long i=1;i<=n;i++)scanf("%lld",&a[i]);
    	for(long long i=1;i<=m;i++){
    		long long l,r;
    		scanf("%lld%lld",&l,&r);
    		vec[l].push_back(r);
    	}
    	for(long long i=1;i<=n;i++){
    		if(vec[i].size()==0)continue;
    		sort(vec[i].begin(),vec[i].end());
    	}
    	for(long long i=1;i<=n;i++){
    		if(vec[i].size()==0)continue;
    		priority_queue<long long> q;
    		priority_queue<long long,vector<long long>,greater<long long> > Q;
    		long long L=i;
    		q.push(a[L]);
    		long long sum1=a[L];
    		long long sum2=0;
    		L++;
    		for(long long j=0;j<=vec[i].size()-1;j++){
    			while(L<=vec[i][j]){
    				if(a[L]>q.top()){
    					Q.push(a[L]);
    					sum2+=a[L];
    				}
    				else {
    					q.push(a[L]);
    					sum1+=a[L];
    				}
    				if(q.size()>Q.size()){
    					while(((L-i+1)+1)/2<q.size()){
    						Q.push(q.top());
    						sum2+=q.top();
    						sum1-=q.top();
    						q.pop();
    					}
    				}
    				else{
    					while(((L-i+1)+1)/2>q.size()){
    						q.push(Q.top());
    						sum2-=Q.top();
    						sum1+=Q.top();
    						Q.pop();
    					}
    				}
    				L++;
    			}
    			ans+=q.top()*(q.size()-Q.size())-sum1+sum2;
    		}
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    【jzoj 1209】拉力赛 (Standard IO)

    Time Limits: 1000 ms $ quad $ Memory Limits: 65536 KB Detailed Limits

    Description

    车展结束后,游乐园决定举办一次盛大的山道拉力赛,平平和韵韵自然也要来参加大赛。
    赛场上共有 $ n $ 个连通的计时点,$ n-1 $ 条赛道(构成了一棵树)。
    每个计时点的高度都不相同(父结点的高 度必然大于子结点),相邻计时点间由赛道相连。
    由于马力不够,所以韵韵的遥控车只能从高处驶向低 处。而且韵韵的车跑完每条赛道都需花费一定的时间。
    举办方共拟举办 m 个赛段的比赛,每次从第 $ u $ 个计时点到第 $ v $ 个计时点,
    当然其中有不少比赛韵韵的遥控车是不能参加的(因为要上坡)。
    平平想知道他能参加多少个赛段的比赛,并且想知道他完成这些赛段的总用时。
     

    Input

    第一行两个整数 $ n,m $ 。
    接下来 $ n-1 $ 行每行 $ 3 $ 个整数 $ a、b、t $ 。
    表示韵韵的遥控车可以花 $ t $ 秒从第 $ a $ 个计时点到第 $ b $ 个计时点。
    接下来 $ m $ 行每行 $ 2 $ 个整数 $ u、v $ ,意义如描述所示。
     

    Output

    第一行输出一个正整数,表示能参加的赛段数。
    第二行输出一个正整数,表示总用时。
     

    Sample Input

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

    Sample Output

     1 
     2
    

     

    Data Constraint

    【数据规模和约定】

    第一个计时点的高度是最高的;
    $ u≠v $ ;
    对于 $ 50 $ %的数据 $ n≤1000 m≤1000 $ ;
    对于 $ 100 $ %的数据 $ n≤10000 m≤100000 $ ;
    答案小于 $ 2^64 $ 。
     

    Solution

    【题意简述】
    对于给定的 $ u、v $ ,判断 $ v $ 是否在以 $ u $ 为根的子树内,并统计“是”的各数。

    对图进行一次 $ dfs $ ,记录每个点第一次被访问到的时间戳 $ begin[i] $ 和完成以这个点围根的树的时间戳 $ finish[i] $ 。
    则 $ u $ 是 $ v $ 的祖先的充要条件是
    $ Begin[u]<begin[v]且finish[v]<finish[u] $
    复杂度:$ O(M+N) $
    期望得分:100

    但是,这题我直接用 $ lca $ 水了,因为 $ v $ 在 $ u $ 的子树内,那么它的 $ lca $ 一定是 $ u $ 啊!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    int read(){
    	char ch; int x=0;
    	while(ch=getchar(),ch<'0'||ch>'9');x=ch-48;
    	while(ch=getchar(),ch>='0'&&ch<='9')x=10*x+ch-48;
    	return x;
    }
    vector<pair<int,int> >e[10005];
    int n,m,dep[10005],f[10005][21];
    ll dis[10005],ans1,ans2;
    void dfs(int u,int fa){
    	dep[u]=dep[fa]+1;
    	f[u][0]=fa;
    	for(int i=1;i<=20;++i)
    		f[u][i]=f[f[u][i-1]][i-1];
    	for(int i=0;i<e[u].size();++i){
    		if(e[u][i].first==fa) continue;
    		dis[e[u][i].first]=dis[u]+e[u][i].second;
    		dfs(e[u][i].first,u);
    	}
    }
    inline int lca(int u,int v){
    	if(dep[u]>dep[v]) swap(u,v);
    	for(int i=20;~i;--i)
    		if(dep[u]<=dep[v]-(1<<i)) v=f[v][i];
    	if(u==v) return u;
    	for(int i=20;~i;--i)
    		if(f[u][i]!=f[v][i]){ u=f[u][i]; v=f[v][i]; }
    	return f[u][0];
    }
    int main(){
    	n=read(); m=read();
    	for(int i=1;i<n;++i){
    		int a=read(),b=read(),t=read();
    		e[a].push_back(make_pair(b,t));
    		e[b].push_back(make_pair(a,t));
    	}
    	dfs(1,0);
    	while(m--){
    		int u=read(),v=read(); 
    		if(lca(u,v)==u){
    			++ans1;
    			ans2+=dis[v]-dis[u];
    		}
    	}
    	printf("%lld
    %lld",ans1,ans2);
    	return 0;
    }
    
  • 相关阅读:
    准备活动
    几个很好的.Net开源框架
    windows 进程通信(使用DDE)(转)
    mysql error 1046 1064 1264 (ERROR大全)
    在版本库里建立版本
    20120206系统日志
    Cocos2dx项目从VS移植到Xcode中的配置
    用python解析JSON
    win10下vc++6.0的安装问题
    Python爬虫(一)抓取指定的页面
  • 原文地址:https://www.cnblogs.com/PotremZ/p/Test20180928.html
Copyright © 2011-2022 走看看