ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

9.13-CSP-S模拟5

2022-09-15 21:30:23  阅读:198  来源: 互联网

标签:int Rep 9.13 long Mu maxn CSP 模拟 define


由于某些原因,现在改为发单篇博客的形式

9.13CSP-S模拟5

T1 F

比较水的一眼题,先没看题观察数据范围发现是n方的,读题发现显然可能合法的x只有\(O(n)\)个,就是拿\(a_1\)和所有的b异或一遍就行了,别的x既然\(a_1\)都异或不出来那显然不可能,对于一个数,它异或另一个数能得到x的话,那么异或的那个数显然是唯一的,于是随便拿个map或者01Trie维护一下剩下的值就行了。我开始还以为它要算合法的排列数

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=2e3+10;

int a[maxn],b[maxn];
vector<int>vec,Ans;
int n;

void Check(int x){
	map<int,int>Mp;
	Rep(i,1,n)Mp[b[i]]++;
	Rep(i,1,n){
		if(Mp.find(a[i]^x)==Mp.end())return;
		if(Mp[a[i]^x]>0)Mp[a[i]^x]--;
		else return;
	}
	Ans.push_back(x);
}

void solve(){
	fre(f);
	cin>>n;
	Rep(i,1,n)cin>>a[i];Rep(i,1,n)cin>>b[i];
	Rep(i,1,n)vec.push_back(a[1]^b[i]);
	sort(vec.begin(),vec.end());vec.erase(unique(vec.begin(),vec.end()),vec.end());
	for(auto it : vec)Check(it);
	cout<<Ans.size()<<"\n";
	for(auto it : Ans)cout<<it<<"\n";
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

T2 S

赛时打了个假dp连暴力分都不如。正解就是枚举前边三种颜色各放了几个,下一个位置要放啥转移,放的时候显然是贪心的拿最近的那个算一下距离就行。

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=4e2+2,INF=20051107;

int f[2][maxn][maxn][3];
bool vis[maxn][maxn];


int n;
char s[maxn];
int a[maxn];
int posr[maxn],posg[maxn],posy[maxn];
int cnt[maxn][3];

void solve(){
	fre(s20);
	cin>>n;cin>>(s+1);
	Rep(i,1,n){
		if(s[i]=='R')posr[++posr[0]]=i;
		if(s[i]=='G')posg[++posg[0]]=i;
		if(s[i]=='Y')posy[++posy[0]]=i;
		cnt[i][0]=posr[0],cnt[i][1]=posg[0],cnt[i][2]=posy[0];
	}
	int now=1;memset(f,0x3f,sizeof(f));
	f[1][1][0][0]=posr[1]-1;
	f[1][0][1][1]=posg[1]-1;
	f[1][0][0][2]=posy[1]-1;
	for(int i=1;i<n;++i){
		memset(f[now^1],0x3f,sizeof(f[now^1]));
		for(int x=0;x<=posr[0];++x){
			if(x>i)break;
			for(int y=0;y<=posg[0];++y){
				if(x+y>i)break;
				int z=i-x-y;
				int dx=posr[x+1]-i-1+max(0,y-cnt[posr[x+1]][1])+max(0,z-cnt[posr[x+1]][2]);
				int dy=posg[y+1]-i-1+max(0,x-cnt[posg[y+1]][0])+max(0,z-cnt[posg[y+1]][2]);
				int dz=posy[z+1]-i-1+max(0,x-cnt[posy[z+1]][0])+max(0,y-cnt[posy[z+1]][1]);
				if(x<posr[0])f[now^1][x+1][y][0]=min({f[now^1][x+1][y][0],f[now][x][y][1]+dx,f[now][x][y][2]+dx});
				if(y<posg[0])f[now^1][x][y+1][1]=min({f[now^1][x][y+1][1],f[now][x][y][0]+dy,f[now][x][y][2]+dy});
				if(z<posy[0])f[now^1][x][y][2]=min({f[now^1][x][y][2],f[now][x][y][0]+dz,f[now][x][y][1]+dz});
			}
		}
		now^=1;
	}
	cout<<min({f[now][posr[0]][posg[0]][0],f[now][posr[0]][posg[0]][1],f[now][posr[0]][posg[0]][2]});
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

T3 Y

所有人都给其后边的人一个球的话,那么相当于没给,所以可以所有人都少给一个球,直到有一个人没有给后边的人球,那么环就可以从此断成链,转移是比较显然的,发现我们断链就是枚举一个起点,从起点推到n,再从1推回这个起点,这两部分内,对于每个i,每次的转移系数都是相同的,于是可以矩阵维护,每次乘一个前后缀矩阵就行了。

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=2e6+10,Mod=1e9+7,inv2=500000004,inv6=166666668;

int n,a[maxn];
ll ans;
//int f[maxn][maxn*10];
#define pre(x) ((x+n-1)%n)
#define nxt(x) ((x+1)%n)

struct Matrix{
	static const int N=2;
	int a[3][3];
	Matrix(){memset(a,0,sizeof(a));}
	void Clear(){memset(a,0,sizeof(a));}
	void Init(){Rep(i,1,N)a[i][i]=1;}
	Matrix operator*(const Matrix &x)const{
		Matrix z;
		for(int i=1;i<=N;i++){
			for(int k=1;k<=N;k++){
				int r=a[i][k];for(int j=1;j<=N;j++)z.a[i][j]=(1LL*x.a[k][j]*r%Mod+z.a[i][j])%Mod;
			}
		}
		return z;
	}
}Mu[maxn],PreMu[maxn],Beg[maxn];

void solve(){
	cin>>n;
	Rep(i,1,n)cin>>a[i];
	reverse(a+1,a+n+1);
	Rep(i,1,n)a[i+n]=a[i];
	Rep(i,1,n){
		Mu[i].a[1][1]=1LL*a[i]*(a[i]+1)%Mod*inv2%Mod;
		Mu[i].a[1][2]=((1LL*a[i]*Mu[i].a[1][1]%Mod-1LL*a[i]*(a[i]+1)%Mod*(2LL*a[i]+1)%Mod*inv6%Mod)%Mod+Mod)%Mod;
		Mu[i].a[2][1]=(a[i]+1);
		Mu[i].a[2][2]=Mu[i].a[1][1];
		Mu[i+n].a[1][1]=(1LL*a[i]*a[i]%Mod-Mu[i].a[1][1]+Mod)%Mod;
		Mu[i+n].a[1][2]=Mu[i].a[1][2];
		Mu[i+n].a[2][1]=a[i];
		Mu[i+n].a[2][2]=Mu[i].a[1][1];
		Beg[i].a[1][1]=1LL*(a[i])*(a[i]+1)%Mod*inv2%Mod;
		Beg[i].a[1][2]=Mu[i].a[1][2];
	}
	Beg[n+1]=Beg[1];
	PreMu[n]=Mu[n];
	Dwn(i,n-1,1)PreMu[i]=Mu[i]*PreMu[i+1];
	PreMu[n+1]=Mu[n+1];
	Rep(i,2,n)PreMu[i+n]=PreMu[i+n-1]*Mu[i+n];
	
	Rep(s,1,n){
		int i=s+1;
		Matrix Ans;Ans.Init();
		if(i==n+1){
			Rep(j,1,n-1)Ans=Ans*Mu[j+n];
			ans=(ans+1LL*Ans.a[1][1]*a[s]%Mod+Ans.a[1][2])%Mod;
			continue;
		}
		Ans=Ans*PreMu[i];
		//Ans=Ans*PreMu[s+n-1];
		if(s>1)Ans=Ans*PreMu[s+n-1];
		ans=(ans+1LL*Ans.a[1][1]*a[s]%Mod+Ans.a[1][2])%Mod;
//		cerr<<ans<<"\n";
	}

/*	Rep(s,1,n){
		memset(f,0,sizeof(f));
		int i=s+1;
		Rep(j,0,a[i])f[i][j]=a[i]-j;
		++i;
		for(;i<=n;++i)Rep(j,0,a[i])Rep(k,0,a[i-1])f[i][j]=(f[i][j]+1LL*(a[i]+k-j)*f[i-1][k])%Mod;
		if(i<=n)i=n+1;
		for(;i<s+n;++i){
			Rep(j,1,a[i])Rep(k,0,a[i-1])f[i][j]=(f[i][j]+1LL*(a[i]+k-j)*f[i-1][k])%Mod;
		}
		i=s+n-1;
		Rep(j,0,a[i])ans=(ans+1LL*f[i][j]*(a[s]+j)%Mod)%Mod;
	}
*/
	cout<<ans<<"\n";
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


T4 O

由于数据很水所以赛时有错误做法过了,于是现在我把错误做法卡掉了。

正解:

我们考虑维护增量,将每一个位置与前边第一个大于它的位置连边,边的权值为大减小,那么我们可以得到一个森林,发现时间线每增加一,就是在树上将每条边的权值向下传递一次,或者可以理解为每条边对应着一个一次函数,这个一次函数在某个位置,并且有限制的定义域。一条边能贡献的位置一定是连续的一段,我们把每条边的贡献离线下来,然后按照时间轴扫。
设一条边的贡献为一个四元组的形式\((p,t,te,d)\)表示这条边从第p个位置,第t秒开始 产生贡献,第te秒时就没有了贡献。于是一次查询实际上就是查询所有的边对查询的位置造成的贡献,考虑把询问差分成求\(l-1\)和\(r\)两个前缀,这样就少了一个边界限制。于是对于一个询问\((x,i)\),即询问第i秒时x位置的前缀和,一条边的贡献就是

\[d*(\min(p+i-t,x)-\min(p,x)) \]

(目前这个式子是不严谨的,后面会说一点细节)
式子的意义就是考虑当前这条边已经扩展到了哪个位置,终点与起点作差算出来扩展了多少个位置,取min是去掉一些不合法的边。
首先,这个式子只对还为终止贡献的边有效,也就是te>当前时间的边,如果一条边已经终止贡献,那么其的贡献形式就变成了一个常函数,直接把它区间加到序列上就行。
其次,对于上边这个式子,我们很完美的把不合法的部分去掉,但是左边的min是终点,右边的min是起点,对于合法的边,我们算区间长度时并没有加一,于是需要特殊考虑一下。
对于上边这个式子,我们把左边的min里的i提出来,变成

\[d*(i+\min(p-t,x-i)-min(p,x)) \]

这样询问的时间就与边无关了,我们就可以静态的维护一些东西。由于取min并不太好搞,于是我们考虑分情况讨论min到底取了谁,用两棵线段树维护\((p-t)*d\) , \(p*d\) ,线段树的下标就分别是\(p\)和\(p-t\),然后对于两种下标,再开两棵线段树维护每个位置上的\(d\),然后我们就可以讨论min取哪一项,然后取出对应的树上的信息算就行,注意当一条边合法的时候,还需要维护d的下标为\(p-t\)那棵树的合法的那一部分再加一次,也就是算区间长度时的那个加一。纯文字描述比较乏力,不懂可以看代码。

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
#define int ll
using namespace std;

const int maxn=5e5+10,LN=-maxn+8,RN=maxn-8,INF=1e9+20051107; 

#define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
const int SZ=1<<21;char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int read(){ gc;while(*ip<'-')gc; bool f=*ip=='-';if(f)gc; int x=*ip&15;gc; while(*ip>'-'){x*=10;x+=*ip&15;gc;} return f ? -x : x; }
struct Seg{
	ll tr[maxn<<2],lazy[maxn<<2];
	void Pushup(int rt){tr[rt]=tr[rt<<1]+tr[rt<<1|1];}
	void Update(int rt,int l,int r,ll w){ tr[rt]+=(r-l+1)*w;lazy[rt]+=w; }
	void Pushdown(int rt,int l,int r){
		int mid=(l+r)>>1;
		Update(rt<<1,l,mid,lazy[rt]),Update(rt<<1|1,mid+1,r,lazy[rt]),lazy[rt]=0;
	}
	void Modify(int rt,int l,int r,int s,int t,ll w){
		if(s<=l && t>=r)return Update(rt,l,r,w);
		int mid=(l+r)>>1;
		if(lazy[rt])Pushdown(rt,l,r);
		if(s<=mid)Modify(rt<<1,l,mid,s,t,w);
		if(t>mid)Modify(rt<<1|1,mid+1,r,s,t,w);
		Pushup(rt);
	}
	int Query(int rt,int l,int r,int s,int t){
		if(s<=l && t>=r)return tr[rt];
		int mid=(l+r)>>1,res=0;
		if(lazy[rt])Pushdown(rt,l,r);	
		if(s<=mid)res+=Query(rt<<1,l,mid,s,t);
		if(t>mid)res+=Query(rt<<1|1,mid+1,r,s,t);
		return res;
	}
}KA,KB,KxA,KxB,C;

int n,q;ll a[maxn>>1],ans[maxn>>1];
int L[maxn>>1],R[maxn>>1];

struct Ver{ 
	int opt,p,t,d; 
	void Print(){cerr<<" Mod :: "<<opt<<" "<<p<<" "<<t<<" "<<d<<"\n";}
};

vector<pii>Q[maxn>>1];
vector<Ver>Op[maxn>>1];

int st[maxn>>1],top;

void Sol(int Tim){
//	cerr<<"Tim :: "<<Tim<<"\n";
	for(auto it : Op[Tim]){
//		it.Print();
		if(it.opt==1){
			KxA.Modify(1,LN,RN,it.p,it.p,it.d);
			KxB.Modify(1,LN,RN,it.p-it.t,it.p-it.t,it.d);
			KA.Modify(1,LN,RN,it.p,it.p,it.p*it.d);
			KB.Modify(1,LN,RN,it.p-it.t,it.p-it.t,(it.p-it.t)*it.d);
		}else{
			KxA.Modify(1,LN,RN,it.p,it.p,-it.d);
			KxB.Modify(1,LN,RN,it.p-it.t,it.p-it.t,-it.d);
			KA.Modify(1,LN,RN,it.p,it.p,-it.p*it.d);
			KB.Modify(1,LN,RN,it.p-it.t,it.p-it.t,-(it.p-it.t)*it.d);
			C.Modify(1,1,n,it.p,it.p+Tim-it.t-1,it.d);
		}
	}
	for(auto it : Q[Tim]){
		int x=it.fir;if(x==0)continue;
		ll res=Tim*KxA.tr[1]+a[x];//+K.Query(1,LN,RN,LN,RN);
		res+=KB.Query(1,LN,RN,LN,x-Tim);
		res+=KxA.Query(1,LN,RN,LN,x);
		res-=KA.Query(1,LN,RN,LN,x);
		res+=KxB.Query(1,LN,RN,x-Tim+1,RN)*(x-Tim);
		res-=KxA.Query(1,LN,RN,x+1,RN)*x;
		res+=C.Query(1,1,n,1,x);
		if(it.sec>0)ans[it.sec]+=res;
		else ans[-it.sec]-=res;
	}
}

void solve(){
	n=read(),q=read();
	Rep(i,1,n)a[i]=read();
	Rep(i,1,n){
		while(top && a[i]>=a[st[top]])R[st[top--]]=i;
		L[i]=st[top];
		st[++top]=i;
	}
	while(top)R[st[top--]]=n+1;
	Rep(i,1,n)if(L[i]){
		int t=i-L[i],d=a[L[i]]-a[i],tx=R[i]-i;
		Op[t].push_back(Ver{1,i,t,d});
		Op[t+tx].push_back(Ver{-1,i,t,d});
	}
	Rep(i,1,q){
		int t,l,r;
		t=read(),l=read(),r=read();
		Q[t].push_back(mair(l-1,-i));
		Q[t].push_back(mair(r,i));
	}
	Rep(i,1,n)a[i]+=a[i-1];
	Rep(i,1,n)Sol(i);
	Rep(i,1,q)printf("%lld\n",ans[i]);
}

#undef int 
int main (){ return solve(),0; }

标签:int,Rep,9.13,long,Mu,maxn,CSP,模拟,define
来源: https://www.cnblogs.com/Delov/p/16698020.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有