• 10.29 正睿停课训练 Day11



    2018.10.29 正睿停课训练 Day11

    比赛链接

    一场rating排名从11掉到40+ ==。掉就掉吧

    状态很迷 全程写T1的。。随机算法。。(一开始就想错了,误以为它正确性很高)
    T2有想法但没调出来
    T3有50暴力但是直接没看==

    A 线段树什么的最讨厌了(思路 DFS)

    题目链接

    容易发现线段树上区间([l,r])的父节点只有(4)种情况:([l,r+len-1],[l,r+len],[l-len-1,r],[l-len,r])
    其实也比较好想,因为只需对父节点区间长度的奇偶性分类讨论一下。
    那么我们可以直接从给定区间([l,r])不断枚举父节点,直到找到一个根节点([0,n])
    显然只有(log)层,那这样是(4^{log n}=n^2)的?注意到有限制为((frac{l}{l-r+1})^2leq2000),所以(n^2)是可过的。(好吧我也不太明白为啥是(frac{l}{l-r+1})?)
    注意要剪枝,不去搜明显不属于线段树上的区间(不然还是暴力分)。

    //371ms	504kb
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    typedef long long LL;
    
    int Ans;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    void DFS(int l,int r)
    {
    	if(l<0||r>=Ans) return;
    	if(!l) {Ans=r; return;}
    	int len=r-l+1;
    	if(l-len>=2*len||!(l-len))DFS(l-len,r);
    	if(l-len>=2*(len+1)||!(l-len-1)) DFS(l-len-1,r);
    	if(l>2*len) DFS(l,r+len);
    	if(l>2*(len-1)) DFS(l,r+len-1);
    }
    
    int main()
    {
    	for(int T=read(); T--; )
    	{
    		int l=read(),r=read(),lim=read();
    		if(l==r) {printf("%d
    ",r); continue;}
    		Ans=lim+1, DFS(l,r), printf("%d
    ",Ans>lim?-1:Ans);
    	}
    	return 0;
    }
    

    B 已经没有什么好害怕的了(差分 前缀和)

    题目链接

    将每个配对的括号表示成([l,r))的形式。
    首先可以将区间([l,r))加一。
    然后对于左端点(l')(r)位置的匹配括号对,显然可以将([l,r))的贡献都加到([l',r'))上;
    对于右端点(r')(l)位置的匹配括号对,显然也可以将([l,r))的贡献都加到([l',r'))上。
    然后就可以神奇差分了。。然后没看懂。。学套路吧。。

    //899ms	21408kb
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define gc() getchar()
    #define mod 1000000007
    #define Mod(x) x>=mod&&(x-=mod)
    #define Add(x,v) (x+=v)>=mod&&(x-=mod)
    typedef long long LL;
    const int N=1e6+5;
    
    int sk[N],L[N],R[N],sum[N],delta[N];
    LL sum2[N];
    char s[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    
    int main()
    {
    	for(int T=read(),n; T--; )
    	{
    		memset(L,0,sizeof L);
    		memset(R,0,sizeof R);
    		memset(sum,0,sizeof sum);
    		memset(delta,0,sizeof delta);
    
    		scanf("%s",s+1), n=strlen(s+1);
    		int top=0;
    		for(int i=1; i<=n; ++i)
    			if(s[i]=='(') sk[++top]=i;
    			else if(top) L[i+1]=sk[top], R[sk[top--]]=i+1;
    		for(int i=n+1; i; --i) sum[L[i]]+=sum[i]+1;
    		for(int i=1; i<=n; ++i) delta[R[i]]+=delta[i]+1;
    		for(int i=1; i<=n; ++i) sum2[i]=sum2[i-1]+sum[i]-delta[i];
    		LL ans=0;
    		for(int i=1; i<=n; ++i) ans+=sum2[i]*i%mod;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    C 我才不是萝莉控呢(DP 贪心 哈夫曼树)

    题目链接

    显然可以(n^2)DP。我们可以从((1,1))DP到((n,1))这样DP就只有两种转移了(不需要考虑下取整),即(f[i][j]=min{f[i-1][j+1], f[i][(j+1)/2]})
    如果你熟悉哈夫曼树,会发现这就类似哈夫曼树的DP转移。(哈夫曼树的DP方法见这儿,也是(n^2)的)
    不是类似,把哈夫曼树的DP过程倒过来就是这个题的走路方式了。
    所以本题等价于求哈夫曼树。用堆就可以(O(nlog n))解决了。
    因为每次合并出的东西单调的,所以二叉哈夫曼树也可以(O(n))解决(见代码)。

    //48ms	1552kb
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=1e5+5;
    
    int n,tot,pa,pb,A[N],B[N<<1];
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline int Get()
    {
    	return (pb>tot||A[pa]<=B[pb])?A[pa++]:B[pb++];
    }
    
    int main()
    {
    	for(int T=read(); T--; )
    	{
    		n=read(),tot=0,pa=pb=1;
    		for(int i=n; i; --i) A[i]=read();
    		LL ans=0; A[n+1]=0x7fffffff;
    		for(int i=1,x,y; i<n; ++i)
    			x=Get(),y=Get(),B[++tot]=x+y,ans+=x+y;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    考试代码

    A

    #include <map>
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define LIM 5000000
    typedef long long LL;
    const int N=5e6+5;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    bool Query(int l,int r,int L,int R)
    {
    	if(l==L&&r==R) return 1;
    	if((L<l&&R>=l)||(L<=r&&R>r)||R<l||L>r||l==r) return 0;
    //	if(L<=l&&r<=R) return 0;
    	int m=(LL)l+r>>1;
    	return Query(l,m,L,R)||Query(m+1,r,L,R);
    }
    void Violence(int l,int r,int lim)
    {
    	for(int i=r; i<=lim; ++i)
    		if(Query(0,i,l,r)) {printf("%d
    ",i); return;}
    	puts("-1");
    }
    //inline int Getpos(int x)
    //{
    //	return x>65536?bit[x>>16]:bit[x];
    //}
    inline int Rand()
    {
    	return (rand()<<16)|rand();
    }
    bool Solve(int L,int R,int lim)
    {
    //	std::map<int,bool> vis;
    	int ans=lim+1;
    	for(int suc=0,mod=lim+1-R,fail=0; suc<=50000&&ans>R; ++suc)
    	{
    		int p=rand()%(ans-R)+R;
    //		if(vis[p])
    //		{
    //			if(++fail>=150000) break;
    //			continue;
    //		}
    //		vis[p]=1;
    		if(Query(0,p,L,R))
    		{
    			ans=std::min(ans,p);
    			for(int i=1; p>>i>=R; ++i)
    				if(Query(0,p>>i,L,R)) ans=std::min(ans,p>>i), ++suc;
    				else break;
    		}
    	}
    	if(ans<=lim)
    	{
    		printf("%d
    ",ans);
    		return 1;
    	}
    	return 0;
    }/*
    3
    521 535 1196
    608 624 3828
    304 314 3650
    1
    990 1755 1080952540
    540 555 2308
    464 475 2833
    */
    int main()
    {
    	freopen("tree.in","r",stdin);
    	freopen("my.out","w",stdout);
    
    //	for(int i=1; i<=65536; ++i)
    //		for(int j=16; ~j; --j)
    //			if(i>>j&1) {bit[i]=j; break;}
    	int t=rand(); srand(t);
    	for(int T=read(),t=1; t<=T; ++t)
    	{
    		int L=read(),R=read(),lim=read();
    		if(R>lim) {puts("-1"); continue;}
    		if(lim<=1000) {Violence(L,R,lim); continue;}
    		if(!Solve(L,R,lim)) puts("-1");
    	}
    	return 0;
    }
    
  • 相关阅读:
    java之集合Collection详解之3
    委托的高级使用
    委托的一般使用
    泛型(Generic)委托
    泛型(Generic)方法(函数,算法)
    泛型(Generic)接口
    泛型(Generic)类的使用原因和使用方式
    C#反射从入门到放弃(这部分遇到的新东西太多了让人接受不能)
    反射应用——依赖注入
    接口的显式实现
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9879363.html
Copyright © 2020-2023  润新知