zoukankan      html  css  js  c++  java
  • test20190815 NOIP2019 模拟题

    100+60+40=200,被后面两个题卡着我很不爽。

    立方数

    【问题描述】
    作为 XX 战队的狂热粉丝,MdZzZZ 看到了自己心仪的队伍在半决赛落败,顿时 心灰意冷。看着自己手中的从黄牛那里抢来的天价总决赛门票,MdZzZZ 觉得去鸟 巢已经没有意义了,于是他决定去跳“水立方”。在他准备进“水立方”体育馆 时,一位大妈拦住了他的去路,并产生了一下对话:

    大妈:“年轻人我看你印堂发黑,恕我冒昧直言,此去一行怕是会有什么不测。”
    MdZzZZ:“大妈别拦我,我要跳水立方发泄一下!”
    大妈:“年轻人,做事要三思而后行,你知道这水立方最著名的是什么吗?”
    MdZzZZ:“不知...”
    大妈:“这水立方最有名的是‘立方数’!”
    MdZzZZ:“哦?”
    大妈:“别急,听我细细道来。‘立方数’就是,如果一个数可以被写作是一个正整数的 3 次方,则这个数就是立方数。例如 1,8,27 就是最小的 3 个立方 数。”
    MdZzZZ:“……”
    大妈:“当然,想要在这水立方中来去自如,你需要知道‘立方差数’!”
    大妈:“若一个数可以被写作是两个立方数的差,则这个数就是‘立方差数’,例如 7(8-1),26(27-1),19(27-8)都是立方差数。如果你能够判断随便一个数是不是‘立方差数’,那么你就可以真正地在这一片小天地中当一条无忧无虑的小鱼...”

    未等 MdZzZZ 反应过来,大妈以飘然远去,留下他一个人在那边细细思索。那么现在你的问题来了,你需要帮助 MdZzZZ 解决这个问题。 现在给定一个数 P,MdZzZZ 想要知道这个数是不是立方差数。

    当然你有可能随机输出一些莫名其妙的东西,因此 MdZzZZ 有 T 次询问~这个问题可能太难了…… 因此 MdZzZZ 规定 P 是个质数!

    【输入格式】
    输入文件名为 cubicp.in。 第一
    行一个数 T,表示有 T 组数据。
    接下来 T 行,每行一个数 P。

    【输出格式】
    输出文件名为 cubicp.out。 输出 T 行,对于每个数如果是立方差数,输出“YES”,否则输出“NO”。

    【输入输出样例 1】
    cubicp.in
    5
    2
    3
    5
    7
    11
    cubicp.out
    NO
    NO
    NO
    YES
    NO

    【数据规模与约定】
    对于 30%的数据 p<=100。
    对于 60%的数据 p<=10^6。
    对于 100%的数据 p<=10^12,T<=100。

    noip2018模拟赛 立方数2

    [p=a^3-b^3=(a-b)(a^2+ab+b^2)\ ecause p in P\ herefore a-b=1,p=a^2+ab+b^2\ herefore a^2+a(a-1)+(a-1)^2=p\ herefore a=frac{3+sqrt{12p-3}}{6} ]

    int main(){
    	freopen("cubicp.in","r",stdin),freopen("cubicp.out","w",stdout);
    	for(int t=read<int>();t--;){
    		LL p=read<LL>();
    		int a=(3+sqrt(12*p-3))/6;
    		puts(p==3LL*a*a-3*a+1?"YES":"NO");
    	}
    	return 0;
    }
    
    

    动态规划

    【问题描述】
    MdZzZZ 在悟得人生终极奥义之后,决定去西藏净化一下自己的灵魂。正当他欣赏沿途的风景之时,突然有一大片羊群闯入了他的视线。

    这时 MdZzZZ 想到了一 个问题,问题是这样的:假如羊群一共有 n 只羊,把它们排成一条直线,并且给 每个羊标上一个价值。定义一段区间的价值为这段区间相同的数的对数。MdZzZZ 想要将这个羊群分成恰好 k 段区间,之后计算这 n 只羊的价值为这 k 段区间的价值 和。MdZzZZ 现在想让最终这 n 只羊的价值和尽可能少。

    例如 6 只羊的价值分别为 1,1,2,2,3,3,现在要将他们切成 3 段。MdZzZZ 立马 想到了一个好方法,分成[1],[1,2],[2,3,3],这样只有第三个区间有 1 的价值。 因此这 6 只羊的价值和为 1。当 MdZzZZ 的思维探索到更多只羊的时候,他不禁陷入 了沉思...然后 MdZzZZ 深深沉迷在思考的世界里面,并且睡着了。

    然而美好的时光总是那么短暂,马上天就要黑了。MdZzZZ 必须要在天黑之前找到旅馆并且住下来。你现在需要帮助 MdZzZZ 解决这个问题,并且尽快把他叫醒。当然你要先解决问题再叫醒他,不然 MdZzZZ 可能会带着起床气一直不肯离开。

    【输入格式】
    输入文件名为 dp.in。
    第一行两个数 n,k。
    接下来一行 n 个数 ai 表示这 n 个数。

    【输出格式】
    输出文件名为 dp.out。
    一个数表示答案。

    【输入输出样例 1】
    dp.in
    10 2
    1 2 1 2 1 2 1 2 1 2
    dp.out
    8

    【数据规模与约定】
    对于 30%的数据 n<=10。
    对于 60%的数据 n<=1000。
    对于 100%的数据 1<=n<=100000,1<=k<=min(n,20),1<=ai<=n。
    其中有 30%的数据满足 ai 完全相同均匀分布在所有数据中。

    CF868F Yet Another Minimization Problem

    先写出DP方程

    [f(i,k)=min_{0 leq j < i} f(j,k-1)+w(j+1,i) ]

    因为(k)很小,所以用不着二分导数斜率。考虑后面那个(w)函数,它满足四边形不等式。

    这个很直观,考虑那个 包含≥交叉 的四条线段的图像,发现你找不出来反例。

    尝试证明(forall a<b)

    [w(a,b+1) + w(a+1,b) geq w(a,b) + w(a+1,b+1) ]

    移项得到

    [w(a,b+1)-w(a,b) geq w(a+1,b+1) - w(a+1,b) ]

    而下面那个差式相当于([a,b])([a+1,b])向右拓展一格的增量,而这个大小关系很显然。

    由于(w)的贡献无法快速计算,所以采用值域分治做法

    设当前的求解区间为([l,r]),最优决策区间([L,R])。对于当前分治的中点(mid),我们需要在([L,min(R,mid)])中暴力找到最优决策(k)。注意到从(w(l,r))(w(l,r+1))或者从(w(l,r))(w(l+1,r))都是可以做到(O(1))的,只要开一个桶记录当前区间每个颜色出现次数就可以啦。把指针(i)(L)移到(min(R,mid))并不断的算(f(i)+w(i,mid)),最终可以找到(k)

    注意一点,当进入求解区间时,我们的应该要确保([L,l−1])的信息的存在,这样才能保证分治的复杂度。

    于是我们考虑进子问题之前如何先处理出子问题的答案。先看左边的子问题(([l,mid−1],[L,k]))显然和当前问题的([L,l−1])是一样的。注意到我们在求(k)的时候对(w)和桶都做了修改,那么我们直接还原回来就可以进左子问题了。

    而右子问题呢?(([mid+1,r],[k,R]))它要预处理的是([k,mid]),而当前的是([L,l−1])。所以我们先把右端点指针从(l−1)移到(mid),桶和(w)都加上去,再把左端点从(L)移到(k),桶和(w)都减掉,接着进去就好了。回溯的时候还是要还原到([L,l−1]),因为上一层要接着用。

    配上LaTeX画图???

    求解区间:(|gets预处理 o| lfrac{qquadqquadqquaddownarrow^{mid}qquadqquadqquad}{}r)
    决策区间:(Lfrac{qquadqquadqquadqquaddownarrow^{k}qquadqquadqquad}{}R)

    时间复杂度(O(nk log n))


    考试的时候还是太naive了,一心想着找出(w)的表达式再来看单调性什么的。没想到可以直接从含义来看……另外我也没有尝试打表。感觉我可能需要掌握更多考试猜想技巧。

    co int N=100000+10;
    int n,k,a[N],b[N];
    LL f[N],g[N];
    
    void solve(int l,int r,int L,int R,LL w){
    	if(l>r) return;
    	int mid=(l+r)>>1,p=min(mid,R),k=0;
    	for(int i=l;i<=mid;++i) w+=b[a[i]]++;
    	for(int i=L;i<=p;++i) w-=--b[a[i]],f[mid]>g[i]+w?f[mid]=g[i]+w,k=i:0;
    	
    	for(int i=l;i<=mid;++i) w-=--b[a[i]];
    	for(int i=L;i<=p;++i) w+=b[a[i]]++;
    	solve(l,mid-1,L,k,w);
    	
    	for(int i=L;i<k;++i) w-=--b[a[i]];
    	for(int i=l;i<=mid;++i) w+=b[a[i]]++;
    	solve(mid+1,r,k,R,w);
    	
    	for(int i=l;i<=mid;++i) --b[a[i]];
    	for(int i=L;i<k;++i) ++b[a[i]];
    }
    int main(){
    	freopen("dp.in","r",stdin),freopen("dp.out","w",stdout);
    	read(n),read(k);
    	for(int i=1;i<=n;++i)
    		g[i]=g[i-1]+b[read(a[i])]++;
    	memset(b,0,sizeof b);
    	while(k--){
    		memset(f,0x3f,sizeof f);
    		solve(1,n,1,n,0);
    		swap(f,g);
    	}
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    
    

    游戏

    【问题描述】
    MdZzZZ 最近十分的苦恼,因为他的好朋友都去玩 Pokemon Go!了,而他向来对这一类的游戏不屑一顾,因此每天都没有人来找他玩。于是 MdZzZZ 自己想了一 个新的游戏,他自豪地将这游戏取名为猜数字游戏。

    游戏规则是这样的:一共有 n 个互不相同的正整数,MdZzZZ 可以每次猜一段 区间的最小值。例如对于某段区间[li,ri]一定会有一个最小值。

    于是他开心的邀请了他的好友 WdZzZZ 来玩这个游戏。令 MdZzZZ 自豪的是,在这个游戏中,他总能构造出一种方案使得 WdZzZZ 满意,直到……WdZzZZ 自己猜的就是矛盾的!例如 WdZzZZ 猜[1,5]的最小值是 2,[1,6]的最小值是 3,这显然就是矛盾的。

    现在你需要帮助 MdZzZZ 判断,在 WdZzZZ 第几次猜数字开始就已经矛盾了。

    【输入格式】
    输入文件名为 number.in。 第一行两个数 n 和 T,
    表示有 n 个数字,LYK 猜了 T 次。
    接下来 T 行,每行三个数分别表示 li,ri 和 xi。

    【输出格式】
    输出文件名为 number.out。 输出一个数表示第几次开始出现矛盾,
    如果一直没出现矛盾输出 T+1。

    【输入输出样例 1】
    number.in
    20 4
    1 10 7
    5 19 7
    3 12 8
    1 20 1

    number.out
    3

    【数据规模与约定】
    对于 50%的数据 n<=8,T<=10。
    对于 80%的数据 n<=1000,T<=1000。
    对于 100%的数据 1<=n,T<=1000000,1<=li<=ri<=n,1<=xi<=n(但并不保证一开始的所有数都是 1~n 的)。

    【Hint】 建议使用读入优化

    ChiTongZ的题解

    直接说正解,将操作离线,然后二分到哪一个操作就挂了,对于当前区间内的操作,把它排序,按照第三权值从大到小。

    考虑哪一些情况是不行的,首先是一个数出现在了两个不相交的区间,其次是权值大的区间覆盖了权值小的区间,然后就没有然后了。

    注意第二种情况要取交集,就是所有权值为当前权值的区间的交集。

    那么对于第一种情况,直接 lmax, rmin 维护出交集就可以了。if (lmax > rmin) return 挂了;

    然后对于第二种情况,标称提供了一种极佳的并查集做法,就是并查集内维护每一个元素 i 延伸最右的点 p。这个是根据每种 x 最后的并集来更新的。

    考虑到排序是从大到小的,若当前的交集为 [lmax,rmin] 并且(可以借助标程理解)find(lmax) > rmin

    由于当前的权值尚未去更新并查集,所以只有之前的区间覆盖当前区间,而之前的区间权值一定更大,所以情况不合法,属于情况二。

    时间复杂度(O(T log T))


    大概这道题的关键在于那些讨论,考试的时候我都没有去尝试骗分……没准就推出正解了。然后比较妙的就是按照权值从大到小来做(机房里讨论认为从小到大做),然后就是用并查集来维护并集。

    co int N=1000000+10;
    int n,T,fa[N];
    struct node{int l,r,x;}p[N],e[N];
    
    il bool operator<(co node&a,co node&b){
    	return a.x>b.x;
    }
    int find(int x){
    	return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    
    bool check(int k){
    	for(int i=1;i<=n+1;++i) fa[i]=i;
    	copy(e+1,e+k+1,p+1),sort(p+1,p+k+1);
    	int lmax=p[1].l,lmin=p[1].l,rmax=p[1].r,rmin=p[1].r;
    	for(int i=2;i<=k;++i){
    		if(p[i].x<p[i-1].x){
    			if(find(lmax)>rmin) return 0; // 交集被覆盖 
    			for(int j=find(lmin);j<=rmax;++j) // 并集合并
    				fa[find(j)]=find(rmax+1);
    			lmin=lmax=p[i].l,rmin=rmax=p[i].r;
    		}
    		else{
    			lmin=min(lmin,p[i].l),lmax=max(lmax,p[i].l);
    			rmin=min(rmin,p[i].r),rmax=max(rmax,p[i].r);
    			if(find(lmax)>rmin) return 0;
    		}
    	}
    	if(find(lmax)>rmin) return 0;
    	return 1;
    }
    int main(){
    	freopen("number.in","r",stdin),freopen("number.out","w",stdout);
    	read(n),read(T);
    	for(int i=1;i<=T;++i) read(e[i].l),read(e[i].r),read(e[i].x);
    	int l=1,r=T;
    	while(l<r){
    		int mid=(l+r+1)>>1;
    		if(check(mid)) l=mid;
    		else r=mid-1;
    	}
    	printf("%d
    ",l+1);
    	return 0;
    }
    
  • 相关阅读:
    mysq 日期相减
    说说时间观与时间管理——北漂18年(71)
    ionic之切换开关
    ionic之单选框
    SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE locks在RR模式下可以看到最新的记录
    14.5.2.3 Consistent Nonlocking Reads 一致性非锁定读
    14.5.2.2 autocommit, Commit, and Rollback
    14.5.2 事务隔离级别
    对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间
    mysql explain 解释
  • 原文地址:https://www.cnblogs.com/autoint/p/test20190815.html
Copyright © 2011-2022 走看看