zoukankan      html  css  js  c++  java
  • [UOJ391] 鸽举选仕

    我把这题推荐给yyb让他把这题做它的T2他竟然不要QwQ.......
    题目大意:
    下发八个题目和对应的八份代码,请构造数据Hack下发代码。

    Task1

    下发代码用了一些神奇做法实现A + B = C这个操作,由于 |A|,|B| <= 100,所以暴力for即可。

    for(int a = -100; a <= 100; a ++)
        for(int b = -100; b <= 100; b ++) {
        	if(ADD(a ^ b, (a & b) << 1) != a + b){
        		cout << a << " " << b << endl , exit(0) ; 
        	}
        }
    

    Task2

    下发代码是按照边数分治的做法,当边数(leq 10^6)时跑(O(m))暴力,当边数(>10^6)时跑(O(n^2))暴力。
    先构造一个大小为(1000)的团让边数超过限制,然后构造一条链每次询问链的两端。
    这样它的复杂度就变成了(O(Qn^2))(5sec)时限妥妥的(TLE)

    n = 5000 ; Q = 10000 ;
    cout << n << " " << Q << endl ;
    for(int i = 2; i <= 1000; i ++) cout << 1 << " " << 1 << " " << i << endl ;
    cout << 1 << " " << 1 << " " << 1001 << endl ;
    for(int j = 1002; j <= 5000; j ++) cout << 1 << " " << j - 1 << " " << j << endl ; 
    for(int j = 5001; j <= 10001; j ++) cout <<2<<" "<< 5000 << " " << 1 << endl ;
    

    Task3

    下发代码就是据说当场(AC)了[CTSC2018]暴力写挂的迭代乱搞做法。
    迭代的做法是:每次选中一个点,找到其最优点,然后跳到那个最优点,接着递归加卡时。
    首先构造一个答案点,然后想办法让迭代的过程中不碰到那两个点。
    我的做法是建两颗形态和边权都一样的树,
    先固定答案点为(x,y),连边((x,z,inf),(y,z,inf),(z,1,-inf))(z)的作用是使得(x,y)深度变为(0)
    然后我们给其他所有点找一个迭代最优点(c),连边:((1,a,0),(a,b,inf-1),(b,c,inf-1))
    为了保证(x,y)不在第一次找点时就被找到,在(1)下面连一堆((t,1,-1))的儿子(t)即可。
    这样不管从哪里出发,迭代若干次后都会到达(c),而(x,y)始终都不会被碰到,自然也就得到了错误答案(2inf-2)

    n = 100000 ; 
    fa[2] = 1 ; e[2] = -inf ; fa[3] = 2 ; e[3] = inf ; fa[4] = 2 ; e[4] = inf ;
    for(int i = 5; i <= 99997; i ++) fa[i] = 1 , e[i] = -1 ;
    fa[99998] = 1 ; e[99998] = 0 ;
    for(int i = 99999; i <= 100000; i ++) fa[i] = i - 1 , e[i] = inf - 1 ;
    cout << 100000 << endl ;
    for(int i = 2; i <= n; i ++) cout <<i <<" "<< fa[i] <<" " << e[i] << endl ; 
    for(int i = 2; i <= n; i ++) cout <<i <<" "<< fa[i] <<" " << e[i] << endl ;
    

    Task4

    先看懂下发程序在干啥,它维护单调栈,对于每一个本质不同的最大值,维护最靠前的位置进行转移。
    它是用单调队列维护的,即若插入决策优于队尾决策,则把队尾弹掉。
    然而对于(j o i),若决策(j)(i)不优,不能说明(j)对之后的决策不优,即没有单调性。
    考虑构造一组数据,让决策点回弹时决策点已经被弹出。
    我们有两个决策点(A,B)和两个转移点(i_1,i_2),我们令(i_1)的最优决策为(B)(i_2)的最优决策为(A)
    由于(A,B)要能够同时存在在单调队列中,所以有:(a_A > a_B > a_{i_1,i_2})
    那么我们要做的就是当加入(f_B + a_{i_1})这个决策时,把(f_A + a_B)这个决策弹掉。
    形式化的:(f_A + a_B ge f_B + a_{i_1})(f_A + a_B < f_B + a_{i_2})
    先考虑(f_B),若(f_B = f_A + a_B),则第一个限制显然假了,所以(f_B)一定是从更靠前的转移点转移过来。
    不妨考虑最简单的一种情况,即到(i_1)时,决策队列中只有(A,B)两个决策。
    要实现这种情况,最简单的办法就是让之前元素都小于等于(A)
    我们直接让(A,B,i_1,i_2)相邻,那么由于(a_A > a_B > a_{i_1,i_2}),所以到了(A)时队列应该是空的。
    这种情况下,(f_A = f_{A - m} + a_A)
    我们已知(f_B eq f_A + a_B),所以(f_B = f_{B - m} + a_B)
    我们现在的限制变为:(f_{A-m} + a_B ge f_{B - m} + a_{i_1})(f_{A-m} + a_B < f_{B -m} + a_{i_2})
    既然现在的数组形如(...ABi_1i_2),一个直接想法就是(m = 3)
    但是有一个问题,我们在程序末尾有一个(f_{i-m} + max(i-m+1...,i-1,i) o f_i)的转移。
    这会导致即时我们把决策(A)弹掉了,(f_{i_2})依旧会用(f_A)更新。
    解决方案就是让(m=4),把(A' = A)设的特别大,然后放形如(...A'A'ABi_1i_2)的序列。
    由于(A'=A)特别大,那么最优情况下一定是把三个(A)划分成一段,那么从(i-m)转移一定不优。
    现在我们只需要让(x = f_{A-m})(y = f_{B-m}),然后放(xyA'A'ABi_1i_2)就行了。
    我们不妨让(x leq y),那么(f_{B-m} = y)(f_{A-m} = x)
    所以限制条件变为:(x + a_B > y + a_{i_1})(x + a_B < y + a_{i_2})(x<y<A>B>a_{i_1,i_2})
    确定了上述限制和序列结构(xyA'A'ABi_1i_2)后就相当好构造了,手玩一下即可。

    n = 8 ; m = 4 ;
    cout << n << " " << m << endl ;
    puts("50 100 1000 1000 1000 500 400 490") ; 
    

    Task5

    选若干区间实际上只需要选两个区间,选更多的显然没用。
    观察一下下发代码,它是几个贪心拼在一起。
    首先把区间去重变为左右端点递增,然后第一个贪心是随机选区间,这个可以直接当作没看见。
    先观察第二个贪心,它是一个不断缩小区间范围的算法。
    再看一下第三个贪心,它选第二个贪心中答案最大的几个右端点,暴力(check)该右端点的所有区间。
    我们的任务:让第二个贪心得不到答案,且答案区间的右端点不是第二个贪心中最大的几个。
    (n = 10^5),固定答案区间为([n-1,n])
    先让前面的区间长度较小,
    然后把第二个贪心右端点(=n)的询问区间打表打出来,发现最小大概([99995,99998])
    任务变为:让(calc(b_n,b_{99998}) < calc(b_n,b_{99997}) < calc(b_n,b_{99996}) < calc(b_n,b_{99995}))
    先让(calc(b_{n-1},b_n) = (10^8)^2 = 10^{16})的级别,那么之前区间的答案不能超过这个数量级。
    显然越大越好处理,那么我们让(b_{99998})(b_{99995})左端点每次加(10^7)
    考虑为了满足上述不等式,这些区间与(n)的交为多少。
    由于向左移动式,区间并在不断增加,所以区间交一定要不断减少。
    (99998)(100000)的交为(Cross),我们考虑每向左一下区间交减少(1)
    那么从(99999)向左(c)个,则(calc(b_{99999-c},b_n) = (len_n + 10^7c)(Cross - c))
    所以(f(c) = -10^7c^2 + (10^7Cross - len_n)c)要单调递增,构造一下(Cross = 10^5)就差不多了。
    我们还不能让右端点为(n)成为第二个贪心中的最大值,让前面的区间答案大概(10^{14})左右数量级即可。

    n = 100000 ; m = 10000000 ; L = 1000000000 ; 
    Cross = 100000 ; 
    sl = L - m * 10 ; sr = L ;
    cout << n << endl ;
    for(int i = 1; i <= 99994; i ++) cout << i <<" "<<i + m <<endl ;
    cout << sl - 5*m << " " << sl + Cross - 5 << endl ;
    cout << sl - 4*m << " " << sl + Cross - 4 << endl ;
    cout << sl - 3*m << " " << sl + Cross - 3 << endl ;
    cout << sl - 2*m << " " << sl + Cross - 2 << endl ;
    cout << sl - 1 << " " << sr - 1 << endl ; cout << sl << " " << sr << endl ;
    

    Task6

    旋转卡壳的经典错误,旋转卡壳不能对凸包上的每一个点求距离其的最远点。
    构造一个宝石形状的凸包即可。

    n = 6 ; cout << n << endl ;
    puts("-8 0") ; puts("-6 -1") ; puts("6 -1") ;
    puts("8 0") ; puts("6 1") ; puts("-6 1") ;
    

    Task7

    你发现这货不就类似什么珂朵莉树,每隔(32)个操作把相同的段都(merge)起来。
    先用(10^4)个区间赋值操作把整个区间变成互不相同的数,
    然后再用(10^4)个区间加法操作让他疯狂(for(i=1 o n))直接卡爆它。

    n = 10000 ; m = 20000 ;
    cout << n << " " << m << endl ;
    for(int i = 1; i <= n; i ++) cout << 0 << " " << i << " " << i << " " << i << endl ;
    for(int i = 1; i <= n; i ++) cout << 1 << " " << 1 << " " << n << " " << 1 << endl ;
    

    Task8

    观察良久发现这个乱搞是这样的:对每个点分别找到(x,y)最近的(frac{60000000}{n})个点,然后建最小生成树。
    那么我们令(n = 10^5),也就是每次找(x,y)相邻的(60)个点。
    首先建两个点((0,0))((61,61))
    接着在它们中间插入(60)((1,inf))((inf,1))
    然后就做完了?把剩下的点放到((inf,inf))来凑数,最后询问一下((0,0))((61,61))就行了。

    n = 100000 ; cout << n << endl ; 
    cout << "0 0" << endl ; cout << "61 61" << endl ; n -= 2 ; 
    for(int i = 1; i <= 600; i ++, -- n) cout << 1 << " 100000" << endl ;
    for(int i = 1; i <= 600; i ++ , --n) cout << "100000" << " " << 1 << endl ;
    while(n --) puts("100000 100000") ;
    Q = 1 ; cout << Q << endl ; puts("1 2") ; 
    

  • 相关阅读:
    ElasticSearch原理
    redis master配置了密码进行主从同步
    redis sentinel 高可用(HA)方案部署,及python应用示例
    Linux Redis集群搭建与集群客户端实现
    字符串倒序
    单链表反转
    【python】面试常考数据结构算法
    面试中的排序算法总结
    Memcached 真的过时了吗?
    Activity生命周期
  • 原文地址:https://www.cnblogs.com/GuessYCB/p/10411938.html
Copyright © 2011-2022 走看看