• EZ 2018 04 13 NOIP2018 模拟赛(八)


    这次的题目都是什么鬼?

    玄学乱搞+肉眼看CODE+倒着搜索?

    好吧是我ZZ了

    链接在此

    T1 玄学乱搞

    由于考场上写的部分分做法忘记讨论n<=2000时的情况,少得了30pts

    很容易得到一个基于排序的算法:

    • 记录每个数的值以及编号

    • 按编号将原数组从大到小排序

    • 对于每一个数,用在它之前的编号最大和最小的分别更新ans

    对于这个算法的正确性显然。因为之前所有点的值都比它大,所以可以稳定确立下min(h[i],h[j])的值,然后记录编号的方式就OK了

    但是这里的数据是1e7,快拍时间复杂度为O(n log2 n)要GG的

    所以很自然地联想到基数排序,由于我姿势水平有限,像LowestJN dalao那样高级的基排,所以只会按位比较的那种

    极限复杂度为:O(n log10 max{a[i]})

    当n=1e7,max{a[i]}=1e9时,总操作数为9e7≈1e8

    理论上机子快一点,常数小一点就可以卡过去了

    然而我太蒟了所以被卡

    这里贴一下Radix_sort的CODE以供参考:

    #include<cstdio>
    #include<cstring>
    const int N=1e7+5;
    using namespace std;
    typedef long long LL;
    struct data
    {
    	int x,id;
    }a[N],temp[N];
    int cnt[15],n,d,MIN,MAX;
    LL ans=-1;
    inline char tc(void)
    {
    	static char fl[100000],*A=fl,*B=fl;
    	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0; char ch=tc();  
    	while (ch<'0'||ch>'9') ch=tc();
    	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    inline int int_max(int a,int b)
    {
    	return a>b?a:b;
    }
    inline int int_min(int a,int b)
    {
    	return a<b?a:b;
    }
    inline int abs(int x)
    {
    	return x>0?x:-x;
    }
    inline LL LL_max(LL a,LL b)
    {
    	return a>b?a:b;
    }
    inline int getbit(int x)
    {
    	int tot=0;
    	if (!x) return 1;
    	while (x) ++tot,x/=10;
    	return tot;
    }
    inline void radix_sort(int n)
    {
    	register int i,j;
    	int radix=1;
    	for (i=1;i<=d;++i,radix*=10)
    	{
    		memset(cnt,0,sizeof(cnt));
    		for (j=1;j<=n;++j)
    		++cnt[(a[j].x/radix)%10];
    		for (j=8;j>=0;--j)
    		cnt[j]+=cnt[j+1];
    		for (j=n;j>=1;--j)
    		temp[cnt[(a[j].x/radix)%10]--]=a[j];
    		memcpy(a,temp,sizeof(a));
    	}
    }
    int main()
    {
    	register int i;
    	//freopen("A.in","r",stdin); freopen("A.out","w",stdout);
    	for (read(n),i=1;i<=n;++i)
    	read(a[i].x),a[i].id=i,d=int_max(d,getbit(a[i].x));
    	radix_sort(n);
    	for (MIN=MAX=a[1].id,i=2;i<=n;++i)
    	ans=LL_max(ans,(LL)int_max(abs(a[i].id-MIN),abs(a[i].id-MAX))*a[i].x),MIN=int_min(MIN,a[i].id),MAX=int_max(MAX,a[i].id);
    	printf("%lld",ans);
    	return 0;
    }
    

    好吧我们来看标算:

    由于我们发现从左往右这种传统的扫描方式难以得出答案,所以我们考虑从两边向中间寻找

    设立l,r表示目前两端的区间范围,所以我们可以用:

    ans=max(ans,(r-l)*min(h[l],h[r]))
    

    来更新ans

    由于min这个操作,为了贪心我们把大的那个数留下来到下一次,即

    if (h[l]<h[r]) ++l; else --r;
    

    这样就实现了O(n)的复杂度

    CODE

    #include<cstdio>
    using namespace std;
    typedef long long LL;
    const int N=1e7+5;
    int a[N],l,r,n;
    LL ans;
    inline char tc(void)
    {
    	static char fl[100000],*A=fl,*B=fl;
    	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0; char ch=tc();
    	while (ch<'0'||ch>'9') ch=tc();
    	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    inline LL max(LL a,LL b)
    {
    	return a>b?a:b;
    }
    inline int min(int a,int b)
    {
    	return a<b?a:b;
    }
    int main()
    {
    	register int i;
    	//freopen("A.in","r",stdin); freopen("A.out","w",stdout);
    	for (read(n),i=1;i<=n;++i)
    	read(a[i]);
    	l=1; r=n;
    	while (l<r)
    	{
    		ans=max(ans,(long long)(r-l)*min(a[l],a[r]));
    		if (a[l]<a[r]) ++l; else --r;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    T2 肉眼看CODE

    我是真的蒙蔽了

    首先%%%XZTdalao肉眼看拿了70+pts

    还有一群初三dalao直接A了此题(据说有人花了2H在看这个)

    不过不知道标算是什么

    听他们说有一个比较可行的算法,就是先rand()一组方案,然后看一下得分。然后根据得分来修改算法

    不过可能要惊人的脚本使用技术耐心

    话说我只认出了姜度dalao的代码,有些人还认出了楼神Manchery

    实为佩服,只能说我输了

    T3 倒着搜索

    这道题其实真的很简单。

    我们先写好DFS爆搜,然后剪剪枝

    接下来开始打表

    然后把枚举的顺序由从小到大改为从大到小即可成功A掉此题(快得飞起)

    这也是什么搜索技巧吗?

    正解:Dancing Link O(n)找规律

    爆搜CODE

    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    int num[55],n,m;
    inline void print(void)
    {
    	for (register int i=1;i<=m;++i)
    	if (!num[i]) putchar('-'); else putchar(num[i]+'A'-1);
    	exit(0);
    }
    inline void DFS(int now)
    {
    	if (!now) print();
    	for (register int i=1;i<=m;++i)
    	if (!num[i])
    	{
    		num[i]=now;
    		if (i+now+1<=m&&!num[i+now+1]) num[i+now+1]=now,DFS(now-1),num[i+now+1]=0;
    		if (i-now-1>=1&&!num[i-now-1]) num[i-now-1]=now,DFS(now-1),num[i-now-1]=0;
    		num[i]=0;
    	}
    }
    int main()
    {
    	scanf("%d",&n); m=n<<1|1;
    	DFS(n);
    	return 0;
    }
    
  • 相关阅读:
    软件工程第一次作业(2)
    软件工程第一次作业
    TR111与STUN
    定制自己的ubuntu 镜像文件 (remastersys, respin, USB live CD)
    上层认证的安全协议 __〈无线局域网安全务实:WPA与802.11i〉读书笔记
    接入控制层的安全协议 __〈无线局域网安全务实:WPA与802.11i〉读书笔记
    WEP 协议__<无线局域网安全务实:WPA与802.11i〉读书笔记
    Python re模块中search与match的区别
    python中如何使用shell命令, 及python 与shell 中的变量相互通信
    sed命令简介及在sed命令中使用变量的方法
  • 原文地址:https://www.cnblogs.com/cjjsb/p/8832886.html
Copyright © 2020-2023  润新知