zoukankan      html  css  js  c++  java
  • 雅礼集训2019 Day5

    雅礼集训2019 Day5

    matrix

    对于同一连续子矩形中的行,我们只计算相同的行中最上面的,那么显然可以分开计算答案。

    从上到下枚举行,再枚举起点,再从左到右枚举这一行中终点所在列,用trie树查询可以做到(O(nm^2))。事实上直接hash也可以。

    然后考虑n^2m做法,考虑容斥,总数-不同子矩形中相等的行数(而且要保证这两行之间没有已经算过的,)

    枚举开头行和另外一行,计算另外的行在以开头行为行首的子矩形中的贡献,显然可以O(m)求出以每个点为右端点的极长相等串,往上枚举的时候取max就不会重。往上一边枚举一边计算答案,为没有被完全包含的列区间数*往下的行数

    那么我们就有了(O(nmsqrt {nm}))的做法,可以过70分:

    #include<bits/stdc++.h>
    #pragma GCC diagnostic error "-std=c++11"
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #pragma GCC optimize("-fgcse")
    #pragma GCC optimize("-fgcse-lm")
    #pragma GCC optimize("-fipa-sra")
    #pragma GCC optimize("-ftree-pre")
    #pragma GCC optimize("-ftree-vrp")
    #pragma GCC optimize("-fpeephole2")
    #pragma GCC optimize("-ffast-math")
    #pragma GCC optimize("-fsched-spec")
    #pragma GCC optimize("unroll-loops")
    #pragma GCC optimize("-falign-jumps")
    #pragma GCC optimize("-falign-loops")
    #pragma GCC optimize("-falign-labels")
    #pragma GCC optimize("-fdevirtualize")
    #pragma GCC optimize("-fcaller-saves")
    #pragma GCC optimize("-fcrossjumping")
    #pragma GCC optimize("-fthread-jumps")
    #pragma GCC optimize("-funroll-loops")
    #pragma GCC optimize("-fwhole-program")
    #pragma GCC optimize("-freorder-blocks")
    #pragma GCC optimize("-fschedule-insns")
    #pragma GCC optimize("inline-functions")
    #pragma GCC optimize("-ftree-tail-merge")
    #pragma GCC optimize("-fschedule-insns2")
    #pragma GCC optimize("-fstrict-aliasing")
    #pragma GCC optimize("-fstrict-overflow")
    #pragma GCC optimize("-falign-functions")
    #pragma GCC optimize("-fcse-skip-blocks")
    #pragma GCC optimize("-fcse-follow-jumps")
    #pragma GCC optimize("-fsched-interblock")
    #pragma GCC optimize("-fpartial-inlining")
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-freorder-functions")
    #pragma GCC optimize("-findirect-inlining")
    #pragma GCC optimize("-fhoist-adjacent-loads")
    #pragma GCC optimize("-frerun-cse-after-loop")
    #pragma GCC optimize("inline-small-functions")
    #pragma GCC optimize("-finline-small-functions")
    #pragma GCC optimize("-ftree-switch-conversion")
    #pragma GCC optimize("-foptimize-sibling-calls")
    #pragma GCC optimize("-fexpensive-optimizations")
    #pragma GCC optimize("-funsafe-loop-optimizations")
    #pragma GCC optimize("inline-functions-called-once")
    #pragma GCC optimize("-fdelete-null-pointer-checks")
    #define FOR(i,a,b) for(register int i=(a);i<=(b);++i) 
    #define ll long long
    #define ull unsigned long long
    using namespace std;
    int read(){
    	int x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x;
    }
    const int N = 5e5+20;
    int n,m;
    vector<int>mp[N];
    namespace sub1{
    	vector<ull>pr[N];
    	ull bas=31;
    	struct node{
    		int nex,pos;ull w;
    	};
    	struct hash_table{
    		int head[20000],top,nh[20000],tp;
    		node edge[20000];
    	//	ull an[N];
    		void pre(){
    			FOR(i,0,n-1){
    				ull res=0,ba=1;
    				for(int j=0;j<=m-1;j++){
    					res=res+1ull*mp[i][j]*ba;ba=ba*bas;
    					pr[i].push_back(res);	
    				}
    			}
    		}
    		ull Hash(int i,int l,int r){
    			ull res=pr[i][r];if(l>0) res-=pr[i][l-1];//res/=
    			return res;
    		}
    		void add(int u,ull w,int pos){
    			edge[++top].w=w;
    			edge[top].pos=pos;
    			edge[top].nex=head[u];
    			head[u]=top;
    		}	
    		int work(int id,int l,int r){
    			ull x=Hash(id,l,r);
    			int now=x%20000,rp=-1;
    			for(int i=head[now];i;i=edge[i].nex){
    				if(edge[i].w==x){
    					rp=edge[i].pos;
    					edge[i].pos=id;
    					break;
    				}
    			}
    			if(rp==-1){
    				if(!head[now]) nh[++tp]=now;
    				add(now,x,id);
    			}
    			return rp;
    		}
    		void clear(){
    			FOR(i,1,tp) nh[i]=head[nh[i]]=0;
    			FOR(i,1,top) edge[i].pos=edge[i].w=edge[i].nex=0;
    			tp=top=0;
    		}
    	}ht;
    	int b[N],tn=0;
    	void solve(){
    		/*FOR(i,0,n-1){
    			FOR(j,0,m-1){
    				b[++tn]=mp[i][j];
    			}
    		} 
    		sort(b+1,b+tn+1);tn=unique(b+1,b+tn+1)-b-1;
    		FOR(i,0,n-1){
    			FOR(j,0,m-1){
    				mp[i][j]=lower_bound(b+1,b+tn+1,mp[i][j])-b;
    			}
    		}*/
    		ll ans=0;
    		ht.pre();
    		FOR(l,0,m-1){
    			FOR(r,l,m-1){
    				ht.clear();
    				FOR(i,0,n-1){
    					int utp=ht.work(i,l,r);
    					/*if(utp!=-1){
    						FOR(p,l,r){
    							assert(mp[i][p]==mp[utp][p]);
    						}
    					}
    					printf("%d %d %d %d
    ",l,r,i,utp);
    					FOR(q,utp+1,i-1){
    							int flg=0;
    							FOR(p,l,r){
    								if(mp[i][p]!=mp[q][p]) flg=1;
    							}
    							
    							assert(flg);
    						}*/
    					//printf("%d %d %d %d
    ",l,r,i,1ll*(i-utp)*(n-i));
    					ans+=1ll*(i-utp)*(n-i);
    				}
    			}
    		}
    		printf("%lld",ans);
    	}
    }
    namespace sub2{
    	int f[N],g[N];
    	void solve(){
    		ll ans=0;
    		FOR(i,0,n-1){
    		//	ans+=(m*(m+1)/2);
    			FOR(k,0,m-1) f[k]=0;
    			for(int j=i-1;j>=0;j--){
    				g[0]=(mp[j][0]==mp[i][0]);
    				FOR(k,1,m-1){
    					if(mp[j][k]==mp[i][k]) g[k]=g[k-1]+1;
    					else g[k]=0;
    				}
    				FOR(k,0,m-1){
    					if(g[k]<=f[k]) continue;
    					else{
    						ans+=1ll*(g[k]-f[k])*(i-j)*(n-i);
    						f[k]=g[k];
    					}
    				}
    			}
    			FOR(k,0,m-1){
    				ans+=1ll*((k+1)-f[k])*(i+1)*(n-i);
    			}
    		}
    		printf("%lld",ans);
    	}
    }
    int main(){
    	freopen("matrix.in","r",stdin);
    	freopen("matrix.out","w",stdout);
    	n=read(),m=read();
    	int flg=0;
    	FOR(i,1,n*m){
    		int x=read();
    		if(x!=i) flg=1;
    		mp[(i-1)/m].push_back(x);
    	}
    	if(!flg){
    		ll ans=0;
    		FOR(i,1,n){
    			FOR(j,1,m){
    				ans+=(1ll*(n-i+1)*(n-i+2)/2ll)*(n-j+1);
    			}
    		}
    		printf("%lld",ans);
    		return 0;
    	}
    	int B=sqrt(1ll*n*m);
    	if(m<=B){
    		sub1::solve();
    	}else sub2::solve();
    	return 0;
    }
    

    然后就不会了orz

    看题解,把我们在trie树上的做法改一下,考虑枚举串长度,那么每次长度加一相当于把trie树根的儿子合并作为新的根,用set启发式合并就可以(nmlog^2n)了,用splay就是(nmlog n)

    sequence

    注意到以一个点开头的序列按位与的值只有最多30种,把这之中整除k的提出来,现在的问题就是(nlog n)个贡献区间,(q)个询问区间,满足(qlleq lleq qr)的要求才能产生贡献,其实(lleq qr)可以去掉,那么排个序+线段树就好了。至于找贡献区间,按数位分类,维护log个指针就好了。

    写完了发现写的是按位或,不过差不了多少(事实上按位或处理更复杂)

    这场才是温暖场啊,昨天那场不咋温暖

    由于我电脑太烂本地跑不过,于是加了O2O3,洛谷测上不开O2随便过

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #define ll long long
    #define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
    using namespace std;
    int read(){
    	int x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x;
    }
    const int N = 1e5+200;
    int n,q,k;
    int a[N];
    vector<int> vec[50];
    int tp[50];
    int t[N],l[N][32],r[N][32];
    ll ans[N*5];
    struct que{
    	int l,r,id;
    	que(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
    }qi[N*5]; 
    int cmp(que a,que b){
    	return a.l>b.l;
    }
    ll d[N*4],tag[N*4];
    inline void push_down(int now,int l,int r){
    	if(tag[now]){
    		int mid=(l+r)>>1;
    		d[now<<1]+=tag[now]*(mid-l+1);
    		tag[now<<1]+=tag[now];
    		d[now<<1|1]+=tag[now]*(r-mid);
    		tag[now<<1|1]+=tag[now];
    		tag[now]=0;
    	}
    }
    inline void push_up(int now){
    	d[now]=d[now<<1]+d[now<<1|1];
    }
    void modify(int now,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr){
    		d[now]+=(r-l+1);tag[now]++;return;
    	} 
    	int mid=(l+r)>>1;push_down(now,l,r);
    	if(ql<=mid) modify(now<<1,l,mid,ql,qr);
    	if(mid<qr) modify(now<<1|1,mid+1,r,ql,qr);
    	push_up(now);
    }
    ll query(int now,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr){
    		return d[now];
    	}
    	int mid=(l+r)>>1;push_down(now,l,r);
    	ll res=0;
    	if(ql<=mid) res=query(now<<1,l,mid,ql,qr);
    	if(mid<qr) res+=query(now<<1|1,mid+1,r,ql,qr);
    	return res;
    }
    void work(int now){
    	FOR(i,1,t[now]){
    		modify(1,1,n,l[now][i],r[now][i]);
    	} 
    }
    inline void out(ll now){
    	if(now>9) out(now/10);
    	putchar('0'+now%10);
    } 
    int main(){
    	freopen("sequence.in","r",stdin);
    	freopen("sequence.out","w",stdout);
    	n=read(),q=read(),k=read();
    	FOR(i,1,n){
    		a[i]=read();
    		FOR(j,0,30){
    			if(!((1<<j)&a[i])) vec[j].push_back(i);
    		}
    	}
    	FOR(i,1,n){
    		int c[32],top=0;
    		FOR(j,0,30){  ////////////////////change
    			if(!((1<<j)&a[i])){
    				tp[j]++;
    			}else if(tp[j]!=vec[j].size()){
    				c[++top]=vec[j][tp[j]];
    			}
    		}
    		sort(c+1,c+top+1);
    		int x=a[i],pos=i;
    		FOR(j,1,top){
    			if(c[j]==c[j-1]) continue;
    			if(x%k==0){
    				l[i][++t[i]]=pos;
    				r[i][t[i]]=c[j]-1;	
    			}
    			x&=a[c[j]];pos=c[j];
    		}
    		if(pos<=n&&x%k==0){
    			l[i][++t[i]]=pos;
    			r[i][t[i]]=n;
    		} 
    	} 
    	//cout<<clock();
    	FOR(i,1,q){
    		int lx=read(),rx=read();
    		qi[i]=que(lx,rx,i);
    	} 
    	sort(qi+1,qi+q+1,cmp);
    	int pos=n;
    	FOR(i,1,q){
    		while(pos>=1&&pos>=qi[i].l){
    			work(pos);
    			pos--;
    		}
    		ans[qi[i].id]=query(1,1,n,qi[i].l,qi[i].r);
    	}
    	FOR(i,1,q){
    		out(ans[i]);putchar(10);
    	}
    	return 0;
    }
    

    permutation

    推了挺久的,考场上不太做得出来(还是题做得不够)

    先考虑最大的数放在哪,接下来两边互不影响,即有a的贡献一定在左边,给b的贡献一定在右边,如果此时知道左右的方案数就可以O(n)算,于是我们现在只用考虑一边

    (f_{j,i})表示jm的数有 (j) 个,一共有 (i) 个数,同样枚举最大的在哪个位置,有转移

    [f_{j,i}=sum_{k=j}^{i-1} f_{j-1,k}{ichoose k} ]

    其实可以扩大范围,因为不满足条件的为0:

    [f_{j,i}=sum_{k=0}^{i-1} f_{j-1,k}frac{i!}{k!(i-k)!} ]

    这可以n^2log,然后就不会了...

    看题解,考虑组合意义,(f_{j,i}=left[^i_j ight]),因为每一个被记入答案的位置的后面几个数一定可以互换。那么求出一行就行了。

  • 相关阅读:
    Designing With Web Standard(一)
    再听姜育恒
    终于找到Effective C Sharp电子版了
    继续下一个题目
    想做就做,要做得漂亮
    空悲还是空杯
    整理,中庸
    分布式系统设计随想
    日志log4
    log4net更换目录
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/13160104.html
Copyright © 2011-2022 走看看