zoukankan      html  css  js  c++  java
  • 2021.2.27模拟赛总结

    开场看A,想了一会发现是个简单的数据结构题。
    但是要写个分块+半平面交。
    由于以前模拟赛场上写分块+半平面交写整场获得0分的好成绩的教训,所以想了一会怎么转成凸包。
    看B后一会想出了80分做法。
    然后想了一会100分,不太会
    然后回头写A。
    A的分块+凸包写的很不自信,写完后一直过不了样例。
    想了一会C,发现也不太会。
    然后写了个裸暴力打算进行对拍,发现裸暴力也错了。
    搞了好久才发现样例错了,浪费了好多时间。
    感觉时间不多了,于是写了个B的20分和C的10分。
    准备写B的80分,但是发现细节有点多。
    感觉离调出A不久了。
    然后就一直调到比赛结束。
    最后只有30分。。。。。
    总结:由于A的样例出错浪费了大量时间。
    而且由于分块好久没写了,导致A调很久。
    这说明以后要多写分块,减少调试时间。
    而且,对计算几何(凸包)不熟悉
    题解:
    A:从小到大枚举(c)
    问题转化成:维护一个数据结构,支持插入一个值,询问(p*a_i),其中(p)(geq i)的有值位置数。
    考虑维护一数组(b),如果插入一个位置(v),把(b_{1...v}++)
    我们需要查询(max(b_i*a_i))
    考虑凸包。我们要支持区间加法。
    对于整块的加法可以预处理出每块的半平面交然后移动指针。
    对于散块的加法考虑重构,我们要把直线(a_ix+y)变成(a_ix+y+v)
    发现斜率是不会变的,所以建立凸包不用排序
    时间复杂度(O(nsqrt{n}))

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define N 100010
    int n,w,mx,ans[N],vi[N],l[N],r[N],ss,bb[N],id[N],tg[N],tt[N];
    struct no{
    	int x,y,id;
    }a[N],b[N];
    int va(no x,int y){
    	return x.x*y+x.y;
    }
    int operator <(no x,no y){
    	return x.y<y.y;
    }
    int cc(no x,no y){
    	return x.x<y.x;
    }
    int cp(no j,no k,no i){
    	return (k.y-j.y)*(i.x-k.x)>=(k.x-j.x)*(i.y-k.y);
    }
    struct hl{
    	no s[500];
    	int tp,pt,l,r,id;
    	void ps(no x){
    		if(tp<2){
    			s[++tp]=x;
    			return;
    		}
    		while(tp>1&&cp(s[tp-1],s[tp],x))
    			tp--;
    		s[++tp]=x;
    	}
    	void rb(){
    		tp=0;
    		for(int i=l;i<=r;i++)
    			if(vi[i]){
    				no va;
    				va.x=b[i].x;
    				va.y=(-tg[id]-tt[i])*b[i].x;
    				ps(va);
    			}
    		pt=1;
    	}
    	int qu(int x){
    		if(!tp)
    			return 0;
    		while(pt<tp&&va(s[pt],x)>=va(s[pt+1],x))
    			pt++;
    		return -va(s[pt],x);
    	}
    }bl[500];
    int qu(){
    	int ans=0;
    	for(int i=1;i<=ss;i++)
    		ans=max(ans,bl[i].qu(-tg[i]));
    	return ans;
    }
    void ad(int c,int d){
    	for(int i=1;i<=ss;i++){
    		if(c<=l[i]&&r[i]<=d)
    			tg[i]++;
    		else if(d>=l[i]){
    			for(int j=max(c,l[i]);j<=min(d,r[i]);j++)
    				tt[j]++;
    			for(int j=l[i];j<=r[i];j++)
    				tt[j]+=tg[i];
    			tg[i]=0;
    			bl[i].rb();
    		}
    	}
    }
    void ins(int x,no y){
    	vi[x]=1;
    	b[x]=y;
    	for(int i=l[bb[x]];i<=r[bb[x]];i++)
    		tt[i]+=tg[bb[x]];
    	tg[bb[x]]=0;
    	bl[bb[x]].rb();
    }
    signed main(){
    	freopen("laofu.in","r",stdin);
    	freopen("laofu.out","w",stdout);
    	scanf("%lld%lld",&n,&w);
    	int bs=sqrt(n),po=1,i=1;
    	while(po<=n){
    		l[i]=po;
    		r[i]=min(po+bs-1,n);
    		po+=bs;
    		i++;
    	}
    	ss=i-1;
    	for(int i=1;i<=ss;i++){
    		bl[i].l=l[i];
    		bl[i].r=r[i];
    		bl[i].id=i;
    	}
    	for(int i=1;i<=ss;i++)
    		for(int j=l[i];j<=r[i];j++)
    			bb[j]=i;
    	for(int i=1;i<=n;i++){
    		scanf("%lld%lld",&a[i].x,&a[i].y);
    		b[i]=a[i];
    		mx=max(mx,a[i].y);
    	}
    	int pt=1;
    	sort(b+1,b+n+1,cc);
    	for(int i=1;i<=n;i++)
    		id[b[i].x]=max(id[b[i].x],i);
    	for(int i=1;i<=n;i++){
    		a[i]=b[i];
    		a[i].id=i;
    	}
    	sort(a+1,a+n+1);
    	for(int i=1;i<=n;i++)
    		b[i].y=b[i].x=0;
    	for(int c=1;c<=mx+1;c++){
    		while(a[pt].y<c&&pt<=n){
    			ins(a[pt].id,a[pt]);
    			ad(1,id[a[pt].x]);
    			pt++;
    		}
    		printf("%lld ",qu()+(n-pt+1)*w*c);
    	}
    }
    

    C:
    看了题解感觉不是很难,但是不知道为什么不会做。
    想到了字符数量取差,想到前缀和就是想不到正解。
    先考虑字符集为(2)的情况,令(f_i)表示(s_{1...i})(a)个数和(b)个数的差。
    一个字符串(s_{j...i})的差是(f_i-f_{j-1}),要求(-k leq f_i-f_{j-1}leq k)
    发现(i,j)调换不影响答案。
    所以合法条件是:(max(f_i)-min(f_i) leq k)
    考虑枚举(min(f_i)),就能知道(max(f_i))的取值范围((min(f_i)+k)),可以用(k)次dp计算。
    (f_{i,j})表示填了(i)个字符,最大值为(j)的答案,可以用矩阵乘法计算。
    发现这样子会算重,(max(f_i)-min(f_i)leq k-1)的会算重。
    所以可以把(k--)再次进行前面的dp。
    发现这样子就不会算重了,因为更小的区间([i,i+l])会被计算((k-l+1)-(k-l)=1)
    回到原问题。令(f_i)表示(s_{1...i})(a)个数和(b)个数的差,(g_i)表示(s_{1...i})(a)个数和(c)个数的差。
    (l1leq f_ileq l1+k,l2leq g_ileq l2+k,l3leq f_i-g_ileq l3+k)
    (f_{i,j,k})表示填了(i)个字符,(a_i=l1+j1,b_i=l2+j2)的个数。
    在转移时需要满足(l3 leq (l1 + j1) − (l2 + j2) leq l3 + k)
    就是(l3-l1+l2leq j1-j2leq l3-l1+l2+k)
    枚举(l3-l1+l2)即可。
    时间复杂度(O(k^7log_2n))
    注意也要容斥。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define mo 998244353
    int ct,n,k,v1,v2,v3,ans,va;
    struct no{
    	int a[40][40];
    }bz,t;
    no operator *(no x,no y){
    	no ans=bz;
    	for(int i=0;i<ct;i++)
    		for(int j=0;j<ct;j++)
    			for(int k=0;k<ct;k++)
    				ans.a[i][j]=(ans.a[i][j]+x.a[i][k]*y.a[k][j]%mo)%mo;
    	return ans;
    }
    no qp(no x,int y){
    	no r=bz;
    	for(int i=0;i<ct;i++)
    		r.a[i][i]=1;
    	for(;y;y>>=1,x=x*x)
    		if(y&1)
    			r=r*x;
    	return r;
    }
    int pd(int s,int a,int b){
    	if(a<0||v2<a||b<0||v3<b||(s-v1>a-b)||(a-b>s))
    		return 0;
    	return 1;
    }
    int gt(){
    	ct=(v2+1)*(v3+1);
    	va=0;
    	for(int s=-k;s<=2*k;s++){
    		t=bz;
    		for(int i=0;i<=v2;i++)
    			for(int j=0;j<=v3;j++)
    				if(s-v1<=i-j&&i-j<=s){
    					int x=i*(v3+1)+j;
    					if(pd(s,i+1,j))
    						t.a[x][x+v3+1]++;
    					if(pd(s,i,j+1))
    						t.a[x][x+1]++;
    					if(pd(s,i-1,j-1))
    						t.a[x][x-v3-2]++;
    				}
    		no vv=qp(t,n);
    		for(int i=0;i<=v1;i++){
    			int a=s-i,b;
    			if(a<=k&&-k<=a){
    				for(int j=0;j<=v2;j++){
    					b=j-a;
    					if(b>=0&&b<=v3&&i-v1<=j-b-a&&j-b-a<=i)
    						for(int l=0;l<ct;l++)
    							va=(va+vv.a[j*(v3+1)+b][l])%mo;
    				}
    			}
    		}
    	}
    	return va;
    }
    signed main(){
    	freopen("baofushehui.in","r",stdin);
    	freopen("baofushehui.out","w",stdout);
    	scanf("%lld%lld",&n,&k);
    	v1=v2=v3=k;
    	ans=gt();
    	v1--;
    	ans=(ans-gt()*3%mo+mo)%mo;
    	v2--;
    	ans=(ans+gt()*3)%mo;
    	v3--;
    	ans=(ans-gt()+mo)%mo;
    	printf("%lld",ans);
    }
    
  • 相关阅读:
    前端总结挺全面的
    cmd与bat脚本的使用
    Spring控制反转(IoC)的理解
    C# 中迭代器
    URL 分页并排序
    结合Flash上传文件时显示进度条
    C# 语言特性
    where T:new()
    图片缩放特效
    C# 隐藏窗体 ALT+TAb不可见
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14456040.html
Copyright © 2011-2022 走看看