• 省选测试34


    总结

    基本上就是暴力分,思维还是需要提升

    A. 老夫

    分析

    将所有元素按照 (b) 从小到大排序

    枚举 (c) 的值,将 (b) 的值小于 (c) 的元素按照 (a) 从小到大排序

    设一共有 (m) 个这样的元素

    那么答案就是 (max((m-i+1) imes a[i]))

    发现每次加入一个新的元素就是把之前所有 (a) 的值小于这个元素的 (i) 的贡献加上 (a[i])

    线段树不大好维护

    可以对序列进行分块构建凸包

    (ans=sum+a[i] imes k)

    (a[i]) 看成 (x),把 (sum) 看成 (y)

    在凸包上二分即可

    新加入一个元素时把当前元素所在的凸包暴力重构

    代码

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    #include<cmath>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e5+5;
    struct jie{
    	int vala,valb,rk;
    }b[maxn];
    bool cmp1(rg jie aa,rg jie bb){
    	return aa.valb<bb.valb;
    }
    bool cmp2(rg jie aa,rg jie bb){
    	return aa.vala<bb.vala;
    }
    int n,w,maxa,maxb,blo,shuyu[maxn],d[maxn],tp,tr[maxn];
    inline int lb(rg int xx){
    	return xx&-xx;
    }
    void ad(rg int wz){
    	for(rg int i=wz;i<=n;i+=lb(i)) tr[i]++;
    }
    int cx(rg int wz){
    	rg int nans=0;
    	for(rg int i=wz;i>0;i-=lb(i)) nans+=tr[i];
    	return nans;
    }
    struct Node{
    	int x,id;
    	long long y;
    	Node(){}
    	Node(rg int aa,rg long long bb,rg int cc){
    		x=aa,y=bb,id=cc;
    	}
    	friend bool operator < (const Node& A,const Node& B){
    		if(A.x==B.x) return A.y<B.y;
    		return A.x<B.x;
    	}
    }sta[maxn],que[maxn];
    std::vector<Node> g[maxn],tmp[maxn];
    double getxl(rg Node aa,rg Node bb){
    	if(aa.x==bb.x){
    		if(bb.y>aa.y) return 1e18;
    		else if(bb.y<aa.y) return -1e18;
    		else return 0;
    	}
    	return (double)(bb.y-aa.y)/(double)(bb.x-aa.x);
    }
    void insert(rg int num){
    	rg int id=shuyu[b[num].rk];
    	tp=0;
    	g[id].clear();
    	if(d[id]) for(rg int i=0;i<tmp[id].size();i++) tmp[id][i].y+=1LL*d[id]*tmp[id][i].x;
    	d[id]=0;
    	ad(b[num].rk);
    	tmp[id].push_back(Node(b[num].vala,1LL*b[num].vala*(cx(n)-cx(b[num].rk-1)),b[num].rk));
    	for(rg int i=0;i<tmp[id].size();i++) if(tmp[id][i].id<b[num].rk) tmp[id][i].y+=tmp[id][i].x;
    	for(rg int i=0;i<tmp[id].size();i++) sta[++tp]=tmp[id][i];
    	std::sort(sta+1,sta+tp+1);
    	rg int tail=1;
    	que[1]=sta[1];
    	for(rg int i=2;i<=tp;i++){
    		while(tail>1 && getxl(que[tail],sta[i])>=getxl(que[tail-1],que[tail])){
    			tail--;
    		}
    		que[++tail]=sta[i];
    	}
    	for(rg int i=1;i<=tail;i++) g[id].push_back(que[i]);
    	for(rg int i=1;i<id;i++) d[i]++;
    }
    long long js(){
    	rg long long nans=0;
    	for(rg int i=1;i<=shuyu[n];i++){
    		if(g[i].size()==0) continue;
    		rg int l=1,r=g[i].size(),mids;
    		while(l<r){
    			mids=(l+r)>>1;
    			if(getxl(g[i][mids-1],g[i][mids])<=-1.0*d[i]) r=mids;
    			else l=mids+1;
    		}
    		l--;
    		nans=std::max(nans,g[i][l].y+1LL*d[i]*g[i][l].x);
    	}
    	return nans;
    }
    int main(){
    	n=read(),w=read();
    	for(rg int i=1;i<=n;i++){
    		b[i].vala=read(),b[i].valb=read();
    		maxa=std::max(maxa,b[i].vala);
    		maxb=std::max(maxb,b[i].valb);
    	}
    	maxb++;
    	std::sort(b+1,b+n+1,cmp2);
    	for(rg int i=1;i<=n;i++) b[i].rk=i;
    	std::sort(b+1,b+n+1,cmp1);
    	blo=sqrt(n);
    	for(rg int i=1;i<=n;i++) shuyu[i]=(i-1)/blo+1;
    	rg int now=1;
    	for(rg int i=1;i<=maxb;i++){
    		while(now<=n && b[now].valb<i){
    			insert(now);
    			now++;
    		}
    		printf("%lld ",js()+1LL*i*w*(n-now+1));
    	}	
    	printf("
    ");
    	return 0;
    }
    

    B. 打算

    分析

    如果按照正常的坐标进行移动,那么在某次操作中,横纵坐标只有一个能够发生变化

    不好处理

    考虑将坐标 ((x,y)) 转化成 ((x+y,x-y)),这样就将两维独立了出来

    横纵坐标可以任意加 (1)(1),并且和原来的坐标变换一一对应

    (s_i) 表示 (i) 时刻的位置

    (s_i=s_{t_i mod L}+s_{L}*lfloor frac{t_i}{L} floor)

    可以写成 (s_{t_i mod L}=As_L+B) 的形式

    按照 (s) 的 下标排序,把相邻两个等式之间作差

    根据时间和路程的关系 (|s_i-s_{i-1}| leq t_i-t_{i-1}),可以解得 (s_L) 的范围

    回代即可求出其它的值

    代码

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #define rg register
    const int maxn=2e6+5;
    const long double orz=1.0;
    int n,l;
    long long t[maxn],x[maxn],y[maxn];
    struct Node{
    	long long a,b,t;
    	Node(){}
    	Node(rg long long aa,rg long long bb,rg long long cc){
    		a=aa,b=bb,t=cc;
    	}
    	friend bool operator < (const Node& A,const Node& B){
    		return A.t<B.t;
    	}
    }jlx[maxn],jly[maxn];
    void bye(){
    	printf("NO
    ");
    	std::exit(0);
    }
    int ansx[maxn],ansy[maxn];
    void solve(rg Node A[],rg long long &L,rg long long &R,rg int ans[]){
    	L=-1e18,R=1e18;
    	for(rg int i=2;i<=n;i++){
    		rg long long nl=A[i-1].t-A[i].t,nr=A[i].t-A[i-1].t,na=A[i].a-A[i-1].a,nb=A[i].b-A[i-1].b;
    		if(na==0){
    			if(nb<nl || nb>nr) bye();
    		} else if(na<0){
    			L=std::max(L,(long long)std::ceil(orz*(nr-nb)/na));
    			R=std::min(R,(long long)std::floor(orz*(nl-nb)/na));
    		} else {
    			L=std::max(L,(long long)std::ceil(orz*(nl-nb)/na));
    			R=std::min(R,(long long)std::floor(orz*(nr-nb)/na));
    		}
    	}
    	if((L+l)&1LL) L++;
    	if((R+l)&1LL) R--;
    	if(L>R) bye();
    	A[1].b+=L*A[1].t;
    	for(rg int i=2;i<=n;i++){
    		A[i].b+=L*A[i].a;
    		if(A[i].t==A[i-1].t) continue;
    		rg long long tmp=A[i-1].t,cz=A[i].b-A[i-1].b;
    		while(cz>0){
    			ans[tmp]=1;
    			tmp++;
    			cz--;
    		}
    		while(cz<0){
    			ans[tmp]=0;
    			tmp++;
    			cz++;
    		}
    		while(tmp+2<=A[i].t){
    			ans[tmp]=1;
    			tmp++;
    			ans[tmp]=0;
    			tmp++;
    		}
    		if(tmp!=A[i].t) bye();
    	}
    }
    int main(){
    	scanf("%d%d",&n,&l);
    	rg long long tmpx,tmpy;
    	for(rg int i=1;i<=n;i++){
    		scanf("%lld%lld%lld",&t[i],&x[i],&y[i]);
    		if((t[i]&1LL)!=((x[i]+y[i])&1LL)) bye();
    		tmpx=x[i]+y[i];
    		tmpy=x[i]-y[i];
    		x[i]=tmpx,y[i]=tmpy;
    	}
    	for(rg int i=1;i<=n;i++){
    		jlx[i]=Node(-1LL*t[i]/l,x[i],t[i]%l);
    		jly[i]=Node(-1LL*t[i]/l,y[i],t[i]%l);
    	}
    	jlx[++n]=Node(0,0,0),jly[++n]=Node(0,0,0);
    	jlx[++n]=Node(1,0,l),jly[++n]=Node(1,0,l);
    	std::sort(jlx+1,jlx+1+n),std::sort(jly+1,jly+1+n);
    	rg long long lx,rx,ly,ry;
    	solve(jlx,lx,rx,ansx);
    	solve(jly,ly,ry,ansy);
    	for(rg int i=0;i<l;i++){
    		if(ansx[i] && ansy[i]) printf("R");
    		else if(ansx[i] && !ansy[i]) printf("U");
    		else if(!ansx[i] && ansy[i]) printf("D");
    		else printf("L");
    	}
    	printf("
    ");
    	return 0;
    }
    

    C. 报复社会

    分析

    考虑字符集只有 (2) 的情况

    设这两种字符分别为 (1,2)

    (g_i=sum1_i-sum2_i),则要求对于任意 (i,j in [0,n]),(g_i)(g_j) 的差值不超过 (k)

    因为 (g_0=0),所以合法的区间为 ([-k,0],[-k+1,1] cdots [0,k])

    然而这样会使一些方案算重,也就是 ([−k+1,0]) 等区间被算了两次,所以要减掉一次

    对于长度更小的区间 ([i,i+l]) ,会被计算 ((k-l+1)-(k-l)=1) 次,恰好被容斥掉了,所以不用考虑

    每一次转移的系数是一样的,所以可以用矩阵快速幂优化

    考虑扩展到字符集为 (3) 的情况

    (g1_i=cnt1_i-cnt3_i,g2_i=cnt2_i-cnt3_i,g3_i=cnt1_i-cnt3_i)

    (g_1) 合法的区间为 ([l_1,l_1+d_1]),(g_2) 合法的区间为 ([l_2,l_2+d_2]),(g_3) 合法的区间为 ([l_3,l_3+d_3])

    (f[o][i][j]) 为当前考虑到第 (o) 个位置,(g1) 和最小值的差为 (i)(g2) 和最小值的差为 (j) 的方案数

    也就是把 (i) 看作 (l_1+i),把 (j) 看作 (l_2+j)

    (g3) 可以由 (g1)(g2) 推得

    为了使 (g_3) 的范围合法,必须满足 (l_3 leq l_1+i-(l_2+j) leq l_3+d_3)

    剩下的就和字符集为 (2) 的一样了

    拿子集反演容斥,奇减偶加

    一共有 (2^3) 种情况,但是本质不同的情况只有 (4)

    代码

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #define rg register
    const int maxn=39,mod=998244353;
    inline int addmod(rg int now1,rg int now2){
    	return now1+=now2,now1>=mod?now1-mod:now1;
    }
    inline int delmod(rg int now1,rg int now2){
    	return now1-=now2,now1<0?now1+mod:now1;
    }
    inline int mulmod(rg long long now1,rg int now2){
    	return now1*=now2,now1>=mod?now1%mod:now1;
    }
    long long n;
    int m,cnt,a[maxn],b[maxn][maxn];
    void mul1(){
    	int tmp[maxn][maxn];
    	memset(tmp,0,sizeof(tmp));
    	for(rg int i=1;i<=cnt;i++){
    		for(rg int j=1;j<=cnt;j++){
    			for(rg int k=1;k<=cnt;k++){
    				tmp[i][j]=addmod(tmp[i][j],mulmod(b[i][k],b[k][j]));
    			}
    		}
    	}
    	memcpy(b,tmp,sizeof(tmp));
    }
    void mul2(){
    	int tmp[maxn];
    	memset(tmp,0,sizeof(tmp));
    	for(rg int i=1;i<=cnt;i++){
    		for(rg int j=1;j<=cnt;j++){
    			tmp[i]=addmod(tmp[i],mulmod(a[j],b[j][i]));
    		}
    	}
    	memcpy(a,tmp,sizeof(tmp));
    }
    int id[maxn][maxn],ans;
    int solve(rg int l1,rg int d1,rg int l2,rg int d2,rg int l3,rg int d3){
    	memset(a,0,sizeof(a));
    	memset(b,0,sizeof(b));
    	memset(id,0,sizeof(id));
    	cnt=0;
    	for(rg int i=0;i<=d1;i++){
    		for(rg int j=0;j<=d2;j++){
    			rg int tmp=(l1+i)-(l2+j);
    			if(tmp>=l3 && tmp<=l3+d3) id[i][j]=++cnt;
    		}
    	}
    	for(rg int i=0;i<=d1;i++){
    		for(rg int j=0;j<=d2;j++){
    			if(id[i][j]){
    				if(id[i+1][j]) b[id[i][j]][id[i+1][j]]++;
    				if(id[i][j+1]) b[id[i][j]][id[i][j+1]]++;
    				if(i && j && id[i-1][j-1]) b[id[i][j]][id[i-1][j-1]]++;
    			}
    		}
    	}
    	a[id[-l1][-l2]]=1;
    	rg long long tmp=n;
    	while(tmp){
    		if(tmp&1LL) mul2();
    		mul1();
    		tmp>>=1LL;
    	}
    	rg int nans=0;
    	for(rg int i=1;i<=cnt;i++) nans=addmod(nans,a[i]);
    	return nans;
    }
    int main(){
    	scanf("%lld%d",&n,&m);
    	for(rg int i=-m;i<=0;i++){
    		for(rg int j=-m;j<=0;j++){
    			for(rg int k=-m;k<=0;k++){
    				ans=addmod(ans,solve(i,m,j,m,k,m));
    			}
    		}
    	}
    	for(rg int i=-m;i<=0;i++){
    		for(rg int j=-m;j<=0;j++){
    			for(rg int k=-m+1;k<=0;k++){
    				ans=delmod(ans,mulmod(3,solve(i,m,j,m,k,m-1)));
    			}
    		}
    	}
    	for(rg int i=-m;i<=0;i++){
    		for(rg int j=-m+1;j<=0;j++){
    			for(rg int k=-m+1;k<=0;k++){
    				ans=addmod(ans,mulmod(3,solve(i,m,j,m-1,k,m-1)));
    			}
    		}
    	}
    	for(rg int i=-m+1;i<=0;i++){
    		for(rg int j=-m+1;j<=0;j++){
    			for(rg int k=-m+1;k<=0;k++){
    				ans=delmod(ans,solve(i,m-1,j,m-1,k,m-1));
    			}
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    在SharePoint中实现Workflow(2):创建一个Workflow
    pku1384PiggyBank(动态规划)
    pku1088滑雪(记忆性搜索)
    hdu1251统计难题(初次接触字典树)
    详细解说 STL 排序(Sort)
    pku1631Bridging signals(动态规划题+二分搜索)
    pku1157LITTLE SHOP OF FLOWERS(简单动态规划题:摆放鲜花使审美价值达到最高)
    pku1067取石子游戏(博弈)
    pku2524Ubiquitous Religions(初次接触并查集)
    pku1050To the Max(求矩阵的最大子段和)
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14471306.html
Copyright © 2020-2023  润新知