• 雅礼集训2017day1乱写


    t1

    区间加,区间除法(下取整),区间最小值,区间求和

    这很显然要用线段树了叭

    其他操作都是线段树常见操作了,只有除法需要动动脑子

    然鹅我们知道一个区间内所有数字应该都只会被除以(log)次(毕竟每次最少减少为(2)倍),所以也许我们可以想一个暴力一点的方法(雾)

    考虑一段区间,例如([4,4,4,5,5,3]),这段区间除以三,那么结果会是([1,1,1,1,1,1]),相当于区间赋值操作!

    还有另一种可能,例如([2,2,3,3]),这段区间除以三,结果是([0,0,1,1]),相当于区间每个数字(-2)

    我们可以把除法操作拆分成这两种操作,对于满足上面两种条件的区间进行操作,复杂度是玄学(反正不会很大)

    为了判断上述操作,还要维护一个区间最大值

    吐槽(loj)(linux)环境不给开(O2)一度认为自己写假了

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define mid ((l+r)>>1)
    #define y1 qwq 
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=1e5+10,inf=0x3f3f3f3f;
    	int n,m,ret;
    	int a[N];
    	int ans[N<<2],minn[N<<2],maxn[N<<2],tag1[N<<2],tag2[N<<2];
    	inline void pushup(int p)
    	{
    		ans[p]=ans[ls(p)]+ans[rs(p)];
    		minn[p]=min(minn[ls(p)],minn[rs(p)]);
    		maxn[p]=max(maxn[ls(p)],maxn[rs(p)]);
    	}
    	inline void build(int l,int r,int p)
    	{
    		tag1[p]=inf;
    		if(l==r)
    		{
    			ans[p]=minn[p]=maxn[p]=a[l];
    			return;
    		}
    		build(l,mid,ls(p));build(mid+1,r,rs(p));
    		pushup(p);
    	}
    	inline void get1(int l,int r,int p,int k)
    	{
    		ans[p]=k*(r-l+1);
    		minn[p]=maxn[p]=tag1[p]=k;
    		tag2[p]=0;
    	}
    	inline void get2(int l,int r,int p,int k)
    	{
    		ans[p]+=k*(r-l+1);
    		minn[p]+=k,maxn[p]+=k;
    		tag2[p]+=k;
    	}
    	inline void pushdown(int l,int r,int p)
    	{
    		if(tag1[p]^inf)
    		{
    			get1(l,mid,ls(p),tag1[p]);
    			get1(mid+1,r,rs(p),tag1[p]);
    			tag1[p]=inf;
    		}
    		if(tag2[p])
    		{
    			get2(l,mid,ls(p),tag2[p]);
    			get2(mid+1,r,rs(p),tag2[p]);
    			tag2[p]=0;
    		}
    	}
    	inline void update1(int tl,int tr,int l,int r,int p,int k)
    	{
    		if(tl<=l&&r<=tr) return get2(l,r,p,k);
    		pushdown(l,r,p);
    		if(tl<=mid) update1(tl,tr,l,mid,ls(p),k);
    		if(tr>mid) update1(tl,tr,mid+1,r,rs(p),k);
    		pushup(p);
    	}
    	inline void update2(int tl,int tr,int l,int r,int p,int d)
    	{
    		if(tl<=l&&r<=tr)
    		{
    			int t1=(int)floor((double)minn[p]/(double)d);
    			int t2=(int)floor((double)maxn[p]/(double)d);
    			if(t1==t2) return get1(l,r,p,t1);
    			if(minn[p]-t1==maxn[p]-t2) return get2(l,r,p,t1-minn[p]);
    		}
    		pushdown(l,r,p);
    		if(tl<=mid) update2(tl,tr,l,mid,ls(p),d);
    		if(tr>mid) update2(tl,tr,mid+1,r,rs(p),d);
    		pushup(p);
    	}
    	inline void query1(int tl,int tr,int l,int r,int p,int &ret)
    	{
    		if(tl<=l&&r<=tr) return(void)(ret=min(ret,minn[p]));
    		pushdown(l,r,p);
    		if(tl<=mid) query1(tl,tr,l,mid,ls(p),ret);
    		if(tr>mid) query1(tl,tr,mid+1,r,rs(p),ret);
    	}
    	inline void query2(int tl,int tr,int l,int r,int p,int &ret)
    	{
    		if(tl<=l&&r<=tr) return(void)(ret+=ans[p]);
    		pushdown(l,r,p);
    		if(tl<=mid) query2(tl,tr,l,mid,ls(p),ret);
    		if(tr>mid) query2(tl,tr,mid+1,r,rs(p),ret);
    	}
    	inline void main()
    	{
    		n=read(),m=read();
    		for(int i=1;i<=n;++i) a[i]=read();
    		build(1,n,1);
    		for(int opt,x,y,i=1;i<=m;++i)
    		{
    			opt=read(),x=read()+1,y=read()+1;
    			if(opt==1) update1(x,y,1,n,1,read());
    			if(opt==2) update2(x,y,1,n,1,read());
    			if(opt==3) {ret=inf;query1(x,y,1,n,1,ret);printf("%lld
    ",ret);}
    			if(opt==4) {ret=0;query2(x,y,1,n,1,ret);printf("%lld
    ",ret);}
    		}
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    

    t2

    比较水的一道构造。。

    先确定方案:先把一整行变成黑色,然后拿一整行去涂每一列

    无解很好判断,如果一开始就没有任何黑色无解,反之一定有解

    我们枚举每一行作为我们选的要变全黑的一整行

    这里要分类讨论

    对于第(i)行,若第(i)列有黑色,则代价为第(i)行白色数量

    若第(i)列没有黑色,就要从其他列借一个,代价为第(i)行白色数量(+1)

    最后加上不是全黑的列数

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define mid ((l+r)>>1)
    #define y1 qwq 
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=1010,inf=0x3f3f3f3f;
    	int n,m,ret,tmp;
    	bool flag;
    	char s[N][N];
    	int s1[N],s2[N];
    	inline void main()
    	{
    		n=read();ret=inf;
    		for(int i=1;i<=n;++i) scanf("%s",s[i]+1);
    		for(int i=1;i<=n;++i)
    		{
    			for(int j=1;j<=n;++j)
    			{
    				if(s[i][j]=='#') ++s1[i],++s2[j],flag=1;
    			}
    		}
    		if(!flag) return(void)puts("-1");
    		for(int i=1;i<=n;++i) tmp+=(s2[i]==n);
    		for(int i=1;i<=n;++i)
    		{
    			if(s2[i]) ret=min(ret,n+n-s1[i]-tmp);
    			else ret=min(ret,n+n-s1[i]+1);
    		}
    		printf("%lld
    ",ret);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    

    t3

    硬核题目,根据题意得到(kq<=m),那么我们不知道想到根号分治

    先对原字符串建出(SAM)(这种东西一看就要(SAM)吧)

    对于(kle sqrt{m})的情况,

    考虑枚举(w)的所有子串,算出在(SAM)上的贡献,把每个询问放入(vector pos[l][r])中,用二分寻找([a,b])内的数量

    具体操作:对于每个位置(i),找到(w[l,i])(SAM)上对应的节点(这里(l)(s)中存在子串的最左侧位置)

    然后枚举(len)的长度,同时对应的节点不断向上跳

    复杂度(O(k^2*q*logn)=O(msqrt{m}logn))

    对于(kge sqrt{m}),则(qle sqrt{m})

    把所有询问((l,r))的长度和编号放入右端点对应的(vector)

    然后用上面的枚举节点的方法,不过把枚举长度变成枚举(r)位置上存储的询问,然后用倍增向上跳到对应长度所代表的子串

    复杂度(O(q*m*logn)=O(msqrt{m}logn))

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define mid ((l+r)>>1)
    #define y1 qwq 
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=2e5+10,inf=0x3f3f3f3f;
    	int n,m,k,q,tot=1,pre=1,lg,rt=1;
    	char s[N];
    	int fa[N],len[N],endpos[N],son[N][26],f[N][20];
    	vector<int> eg[N];
    	inline void insert(int c)
    	{
    		int p=pre,np=pre=++tot;endpos[tot]=1;
    		len[np]=len[p]+1;
    		for(;p&&!son[p][c];p=fa[p]) son[p][c]=np;
    		if(!p) fa[np]=rt;
    		else
    		{
    			int q=son[p][c];
    			if(len[q]==len[p]+1) fa[np]=q;
    			else
    			{
    				int nq=++tot;
    				for(int i=0;i<26;++i) son[nq][i]=son[q][i];
    				len[nq]=len[p]+1;
    				fa[nq]=fa[q];
    				fa[q]=fa[np]=nq;
    				for(;p&&son[p][c]==q;p=fa[p]) son[p][c]=nq;
    			}
    		}
    	}
    	inline void sakura(int now)
    	{
    		for(int i=1;i<=19;++i) f[now][i]=f[f[now][i-1]][i-1];
    		for(auto t:eg[now])
    		{
    			f[t][0]=now;
    			sakura(t);
    			endpos[now]+=endpos[t];
    		}	
    	}
    	namespace solve1
    	{
    		vector<int> pos[350][350];
    		inline void main()
    		{
    			for(int l,r,i=0;i<m;++i)
    			{
    				l=read(),r=read();
    				pos[l][r].push_back(i);
    			}
    			while(q--)
    			{
    				scanf("%s",s);
    				int a=read(),b=read();
    				int cur=rt,curlen=0;
    				int ans=0;
    				for(int i=0;i<k;++i)
    				{
    					while(cur!=rt&&!son[cur][s[i]-'a'])
    						cur=fa[cur],curlen=min(curlen,len[cur]);
    					if(son[cur][s[i]-'a'])
    					{
    						cur=son[cur][s[i]-'a']; 
    						++curlen;
    						int now=cur;
    						for(int plen=curlen;plen;--plen)
    						{
    							while(len[fa[now]]>=plen) now=fa[now];
    							auto& q=pos[i-plen+1][i];
    							auto l=lower_bound(q.begin(),q.end(),a);
    							auto r=upper_bound(q.begin(),q.end(),b);
    							int cnt=r-l;
    							ans+=cnt*endpos[now];
    						}
    					}
    				}
    				printf("%lld
    ",ans);
    			}
    		}
    	}
    	namespace solve2
    	{
    		typedef pair<int,int> p;
    		vector<p> qlen[N];
    		inline void main()
    		{
    			for(int l,r,i=0;i<m;++i)
    			{
    				l=read(),r=read();
    				qlen[r].push_back(p(r-l+1,i));
    			}
    			while(q--)
    			{
    				scanf("%s",s);
    				int a=read(),b=read();
    				int cur=rt,curlen=0;
    				int ans=0;
    				for(int i=0;i<k;++i)
    				{
    					while(cur!=rt&&!son[cur][s[i]-'a'])
    						cur=fa[cur],curlen=min(curlen,len[cur]);
    					if(son[cur][s[i]-'a'])
    					{
    						cur=son[cur][s[i]-'a'];
    						++curlen;
    						for(auto q:qlen[i])
    						{
    							if(q.second<a||q.second>b) continue;
    							if(curlen<q.first) continue;
    							int now=cur;
    							for(int j=19;~j;--j)
    								if(len[f[now][j]]>=q.first) now=f[now][j];
    							ans+=endpos[now];
    						}
    					}
    				}
    				printf("%lld
    ",ans);
    			}
    		}
    	}
    	inline void main()
    	{
    		n=read(),m=read(),q=read(),k=read();
    		scanf("%s",s);
    		for(int i=0;i<n;++i) insert(s[i]-'a');
    		for(int i=2;i<=tot;++i) eg[fa[i]].push_back(i);
    		sakura(rt);
    		if(k<=333) solve1::main();
    		else solve2::main();
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    
  • 相关阅读:
    .NET中如何有效的使用Cache
    Page_Load与Page_PreRender的执行顺序
    TextBox取不到值及其TextBox取不到js赋的值
    Repeater用ul li,一行显示多条数据
    [转].net创建XML文件的两种方法
    【ABAP系列】SAP Web Dynpro 技术简介
    【SD系列】SAP SD模块-送达方和售达方的区别和联系
    【FICO系列】SAP FI模块-记账凭证FB01的BAPI
    【公众号系列】SAP 主要模块及简介
    【ABAP系列】SAP ABAP同时显示多个ALV的方法
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12735197.html
Copyright © 2020-2023  润新知