2018.07.19【2018提高组】模拟C组

前言:

早上完全起不来了,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 ,所以很容易发现系数以及常数项都是斐波那契数列,所以容易得出代码


代码

#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 的学生,把他们分班,必须按照学号顺序,问在满足所有班的欠扁最高值之和不得超过Limit下,女友数之和最多的班级答案最小,保证有解


分析

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

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/81114627