2018.07.19【2018提高组】模拟C组

111 篇文章 0 订阅
99 篇文章 1 订阅

前言:

早上完全起不来了,9点被回来的舍友叫醒,orz


JZOJ 3461 小麦亩产一千八

题目

假设第0个格子有1粒麦子,第1个格子有p粒麦子,之后每一个格子放入前两个格子的小麦数之和的小麦,若第a个格子有x粒麦子,问是否存在p,若存在,问第b个格子有多少粒麦子,否则输出-1(给出a,x,p)


分析

按照这样,得到数列 1 , p , p + 1 , 2 p + 1 , 3 p + 2 , 5 p + 3 , 8 p + 5 … … 1,p,p+1,2p+1,3p+2,5p+3,8p+5…… 1,p,p+1,2p+1,3p+2,5p+3,8p+5,所以很容易发现系数以及常数项都是斐波那契数列,所以容易得出代码


代码

#include <cstdio>
using namespace std;
long long a,x,b,f[21]={0,1};
int main(){
	for (int i=2;i<=20;i++) f[i]=f[i-1]+f[i-2];
	while (scanf("%lld%lld%lld",&a,&x,&b)==3){
		if ((x-f[a-1])%f[a]) puts("-1");//不存在p粒麦子的情况
		else{
			int z=(x-f[a-1])/f[a];//找到p
			printf("%lld\n",f[b]*z+f[b-1]);//输出答案
		} 
	}
	return 0;
}

JZOJ 3462 休息

题目

每一次将所有的书划分为尽量少的连续部分,使得每一部分的书的高度都是单调下降,然后将其中所有不少于2 本书的区间全部翻转。重复执行以上操作,最后使得书的高度全部单调上升。问最少需要翻转多少次。


分析

做第一次翻转,再求逆序对。
Reason:因为不能保证直接求逆序对是最优的,所以要模拟第一次翻转,then为什么要求逆序对,因为把单调上升连续子序列转变后,那么再翻转就是在中间翻转,所以直接求逆序对就行了。


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int n,a[100001],b[100001]; long long ans;
int in(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void merge(int l,int mid,int r){
    int low=l,high=mid+1,x=0;
    while (low<=mid&&high<=r){
        if (a[low]<=a[high]) b[++x]=a[low++];
        else b[++x]=a[high++],ans+=mid-low+1;//求逆序对
    }
    while (low<=mid) b[++x]=a[low++];
    while (high<=r) b[++x]=a[high++];
    for (int j=1;j<=x;j++) a[l+j-1]=b[j];
}
void mergesort(int l,int r){
    if (l<r){
        int mid=(l+r)/2;
        mergesort(l,mid);
        mergesort(mid+1,r);
        merge(l,mid,r);
    }
}
int main(){
	n=in(); int j=1;
	for (int i=1;i<=n;i++) a[i]=in();
	for (int i=1;i<n;i++)
	if (a[i]<a[i+1]){
		if (i-j>=1) for (int k=j;k<=(j+i)>>1;k++) //翻转
		a[k]^=a[i-k+j],a[i-k+j]^=a[k],a[k]^=a[i-k+j]; 
		if (i-j>=1) ans++; j=i+1;
	}
	if (n-j>=1) for (int k=j;k<=(j+n)>>1;k++) //翻转
	a[k]^=a[n-k+j],a[n-k+j]^=a[k],a[k]^=a[n-k+j]; 
	if (n-j>=1) ans++; mergesort(1,n);//归并排序
	return !printf("%lld",ans);
}

#JZOJ 3463 军训

题目

学号为 1 − n 1-n 1n的学生,把他们分班,必须按照学号顺序,问在满足所有班的欠扁最高值之和不得超过Limit下,女友数之和最多的班级答案最小,保证有解


分析

二分女友数的答案,然后 d p dp dp f [ i ] f[i] f[i]表示分到学号 i i i时的欠扁最高值之和,then再用队列维护当前的班级,当然还要用 S T L STL STL中高级的 m u l t i s e t multiset multiset红黑树,满足删除,插入,查询是否存在或相等。
为什么要这么做,因为当枚举 j ∣ 1 ≤ j ≤ i j|1\leq j\leq i j1ji时会相对应增加时间,所以可以用骚操作找出最优的 j j j


代码

#include <cstdio>
#include <cctype>
#include <set>
using namespace std; multiset<int>ms;
int n,l,r,lrp,s[20001],rp[20001],f[20001],q[20001];
int in(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int min(int a,int b){return (a<b)?a:b;}
int max(int a,int b){return (a>b)?a:b;}
bool check(int mid){
	f[0]=0; int x,y,j=1,head=1,tail=1; ms.clear();
	for (int i=1;i<=n;i++){
		while (s[i]-s[j-1]>mid) j++;//找出合法的j
		while (head<tail&&q[head]<j){//出队
		    if (head+1<tail) 
			    ms.erase(ms.find(f[q[head]]+rp[q[head+1]]));//删除不合法
		    head++;
		}
		while (head<tail&&rp[q[tail-1]]<=rp[i]){//如果当前最大值不满足
			if (head+1<tail&&ms.find(f[q[tail-2]]+rp[q[tail-1]])!=ms.end()) 
			   ms.erase(ms.find(f[q[tail-2]]+rp[q[tail-1]]));//出队
            tail--;
		}
		q[tail++]=i; if (head+1<tail) ms.insert(f[q[tail-2]]+rp[i]);//找出新的可能
		f[i]=f[j-1]+rp[q[head]]; if (!ms.empty()) f[i]=min(f[i],*ms.begin());//dp
	}
	return f[n]<=lrp;//在范围内
}
int main(){
	n=in(); lrp=in(); int x;
	for (int i=1;i<=n;i++) rp[i]=in(),x=in(),s[i]=s[i-1]+x,l=max(l,x); r=s[n];//l是最大的女友值,r是总和(分成一个班)
	while (l<r){//二分(最大值最小)
		int mid=(l+r)>>1;
		if (check(mid)) r=mid; else l=mid+1;
	}                                
	return !printf("%d",l);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
}

JZOJ 3464 秀姿势

题目

一个序列,删去 k k k个数字,使连续且相同的子序列最长。


分析

用一个队列维护当前 k k k个数字,用 s s s存下队列中不同的数字,并用哈希统计答案


代码

#include <cstdio>
#include <cctype>
#include <queue>
#define p 200003
#define max(a,b) (a>b)?a:b
using namespace std;
int n,k,x,ans,hash[p],sash[p],s; queue<int>q;
int in(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int locate(int x){
	int pos=x%p,i=0;
	while (i<p&&hash[(pos+i)%p]&&hash[(pos+i)%p]!=x) i++;
	return (pos+i)%p;
}
int main(){
	n=in(); k=in();
	for (int i=1;i<=n;i++){
		x=in(); int pos=locate(x); q.push(x);//进入队列
		if (!sash[pos]){//该数字不存在
		    hash[pos]=x; s++;//加入
	        while (s>k+1){//只能有k个不同的数字
	    	    int pos1=locate(q.front()); q.pop(); 
	    	    sash[pos1]--; if (!sash[pos1]) hash[pos1]=0,s--;//删除
		    }
		} 
		sash[pos]++; ans=max(ans,sash[pos]); //统计答案
	}
	return !printf("%d",ans);
}

后续:OTL

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值