• 2022“杭电杯”中国大学生算法设计超级联赛(2)部分题题解


    ShuanQ

    这个题告诉我们没事别瞎用PR,还是可能会被卡掉的...
    考虑M一定是P*Q-1的因子,并且是质数,考虑分解质因子。然后这个题就没了...
    (没啥事别枚举因子,判断是不是质数....)

    Luxury cruise ship

    考虑一个数能不能用7,31,365拼成。可以发现365可以被7,31构成.(365=1131+27).所以我们考虑底层都是由7和31构成,之后我们尝试将他们成对的拿出,每次拿出11个31和2个7,这样就构成了365.那考虑拿到最后,只会剩下31和7凑不成一对的情况。可以发现这种情况并不多,并且凑不成一对的情况表示的数字很有限。所以我们可以直接预处理出来小数据的情况。大数据先用365去凑,之后再用我们处理的小数据即可。

    Static Query on Tree

    树剖,A,B,C分开考虑,打三个标记。不多说了(打了180多行,真NM...)

    DOS Card

    这个题又拓展了我对线段树区间可加性的认知。
    考虑区间是否可加,我们发现答案只能是两种形式,+-+-和++--.
    首先考虑第一种情况,我们+-+-划分,可以得知区间内需要维护的值有,两对的最大值,最大值,一对减去剩下的最小值,一对的最大值,一对的值加上剩下的最大值。
    考虑++--的划分,有最大值,次大值,最小值,次小值,一对加上剩下的最大值,一对减上剩下的最小值。
    综上所述:我们需要:
    最大值,次大值,最小值,次小值,一对的最大值,二对的最大值,一对的值加上剩下最大值,一对的值减去剩下最小值。依次去更新即可。
    友情提示:细节真NM的多。。。

    点击查看代码
    #include<bits/stdc++.h>
    #define ls p<<1
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    const ll INF=2e17;
    int n,m,a[N];
    struct Tree
    {
    	int l,r;
    	ll mx,mxx,mn,mnn,yi,er,yia,yin;
    	#define l(p) t[p].l
    	#define r(p) t[p].r
    	#define mx(p) t[p].mx
    	#define mn(p) t[p].mn
    	#define mxx(p) t[p].mxx
    	#define mnn(p) t[p].mnn
    	#define yi(p) t[p].yi
    	#define er(p) t[p].er
    	#define yia(p) t[p].yia
    	#define yin(p) t[p].yin
    	Tree friend operator +(Tree a,Tree b)
    	{
    		Tree c;
    		c.l=a.l;c.r=b.r;
    		ll A[4]={a.mx,a.mxx,b.mx,b.mxx};
    		sort(A,A+4,[&](ll x,ll y){return x>y;});
    		c.mx=A[0];c.mxx=A[1];
    		ll B[4]={a.mn,a.mnn,b.mn,b.mnn};
    		sort(B,B+4);
    		c.mn=B[0];c.mnn=B[1];
    		c.yi=max(max(a.yi,b.yi),a.mx-b.mn);
    		c.er=max(max(a.er,b.er),a.mx+b.yin);	
    		c.er=max(c.er,a.yia-b.mn);
    		if(a.r-a.l>=1&&b.r-b.l>=1) c.er=max(c.er,a.mx+a.mxx-b.mn-b.mnn);
    		c.er=max(c.er,a.yi+b.yi);
    		c.yia=max(max(a.yia,b.yia),a.yi+b.mx);
    		if(b.r-b.l>=1)c.yia=max(c.yia,a.mx+b.mx-b.mn);
    		if(a.r-a.l>=1)c.yia=max(c.yia,a.mx+a.mxx-b.mn);
    		c.yin=max(max(a.yin,b.yin),b.yi-a.mn);
    		if(b.r-b.l>=1)c.yin=max(c.yin,a.mx-b.mn-b.mnn);
    		if(a.r-a.l>=1)c.yin=max(c.yin,a.mx-a.mn-b.mn);
    		return c; 
    	}
    }t[N<<2];
    inline void build(int p,int l,int r)
    {
    	if(l==r)
    	{
    		l(p)=r(p)=l;
    		mx(p)=mn(p)=(ll)a[l]*a[l];
    		mxx(p)=-INF;
    		mnn(p)=INF;
    		yi(p)=-INF;
    		er(p)=-INF;
    		yia(p)=-INF;
    		yin(p)=-INF;
    		return;
    	}
    	int mid=l+r>>1;
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    	t[p]=t[ls]+t[rs];
    }
    inline Tree ask(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p)) return t[p];
    	int mid=l(p)+r(p)>>1;
    	if(r<=mid) return ask(ls,l,r);
    	if(l>mid) return ask(rs,l,r);
    	return ask(ls,l,r)+ask(rs,l,r);
    }
    int main()
    {
    //	freopen("1.in","r",stdin);
    	int T;scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    		build(1,1,n);
    		for(int i=1;i<=m;++i)
    		{
    			int l,r;scanf("%d%d",&l,&r);
    			printf("%lld\n",ask(1,l,r).er);
    		} 	
    	}
    	return 0;
    }
    

    Copy

    怎么说呢,这个题感觉思维性还是很有强度的。
    首先我们特别要注意的是这道题的数据范围,可以发现每次操作的区间都是在n范围内。这提醒我们操作超过n时,可以直接舍弃。其次我们考虑异或的性质,两个相同的数异或答案是0,会抵消。说明我们只需要知道在原数列,每个数是否参与了异或即可。考虑操作1的过程,是将某个区间给分开了,这对我们统计某个数的奇偶有很大问题.我们尝试倒着看这个过程。正着看是分开,倒着看是合并。(对于一道题目而言,合并比分开简单).并且这个合并也简单,只需要将l+1到n的数向左移区间长度即可.我们用bitset去表示每一位参与异或的结果。倒着做这个过程。

    点击查看代码
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    int n,q,a[N];
    bitset<N>ans;
    struct wy{int l,r,op;}b[N];
    inline void solve()
    {
    	ans.reset();
    	scanf("%d%d",&n,&q);
    	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    	for(int i=1;i<=q;++i)
    	{
    		scanf("%d%d",&b[i].op,&b[i].l);
    		if(b[i].op==1) scanf("%d",&b[i].r);
    	} 
    	for(int i=q;i>=1;--i)
    	{
    		int l=b[i].l,r=b[i].r;
    		if(b[i].op==1)
    		{
    			auto a=ans&((~bitset<N>(0))>>(N-r-1));
    			auto b=ans&((~bitset<N>(0))<<(r+1));
    			ans=a^(b>>(r-l+1));
    		}
    		else ans[l]=ans[l]^1;
    	}
    	int res=0;
    	for(int i=1;i<=n;++i) if(ans[i]) res^=a[i];
    	printf("%d\n",res);
    }
    int main()
    {
    //	freopen("1.in","r",stdin);
    	int T;scanf("%d",&T);
    	while(T--) solve();
    	return 0;
    } 
    
  • 相关阅读:
    Oracle Drop表并未直接删除 drop table xx purge
    Notepad++使用
    Python使用MySQL数据库
    考驾照科目二科目三要点记录
    Linux中权限(r、w、x)对于目录与文件的意义
    linux之expr命令
    linux下scp
    数字货币和区块链联系
    网站
    关于linux 编程
  • 原文地址:https://www.cnblogs.com/gcfer/p/16503378.html
Copyright © 2020-2023  润新知