190921 CSP-S 2019模拟

l d x ldx ldx 爆零过程在这里~

A

数数题
考虑到一个性质是对于每个数,最多存在一个 ≤ 15 \le15 15 的质因子,这样可以将所有数按照其 ≥ 15 \ge15 15 的质因子分组,设 f i , a 1 , a 2 , a 3 , a 4 , a 5 , a 6 f_{i,a_1,a_2,a_3,a_4,a_5,a_6} fi,a1,a2,a3,a4,a5,a6 表示前 i i i 组,它们的 l c m lcm lcm 2 , 3 , 5 , 7 , 11 , 13 2,3,5,7,11,13 2,3,5,7,11,13 的幂次分别为 a 1 , a 2 , a 3 , a 4 , a 5 , a 6 a_1,a_2,a_3,a_4,a_5,a_6 a1,a2,a3,a4,a5,a6 的所有 l c m lcm lcm 和,然后枚举第 i + 1 i+1 i+1 组中的每个数转移,注意可以前缀和优化
CODE:

#include
#define ri register int
#define fi first
#define se second
#define pb push_back
#define rsz resize
#define sz(x) (int)(x).size()
#define lb lower_bound
#define rb upper_bound
#define all(x) (x).begin(),(x).end()
using namespace std;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
typedef long long ll;
const int mod=1e9+7;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?0:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):0;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))(p&1)&&(Mul(ret,a),1);return ret;}
const int N=2005;
int n,a[N];
int pri[41]={17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,1};
int f[8][5][4][3][3][3],g[8][5][4][3][3][3],ss[8][5][4][3][3][3];
vector<int>vl[41];
int main(){
	n=read();
	for(ri i=1;i<=n;++i)a[i]=read();
	for(ri ff=0,i=1;i<=n;++i,ff=0)for(ri j=0;j<41;++j)
	if(a[i]==a[i]/pri[j]*pri[j]){a[i]/=pri[j],vl[j].pb(a[i]);break;}
	f[0][0][0][0][0][0]=1;
	int res=0;
	for(ri mt,t,b1,b2,b3,b4,b5,b6,vlx,i=40;~i;--i){
		if(!vl[i].size())continue;
		memset(ss,0,sizeof(ss));
		for(ri j=0,up=vl[i].size();j<up;++j){
			memset(g,0,sizeof(g));
			mt=1,b1=b2=b3=b4=b5=b6=0;
			t=vl[i][j];
			while(t%2==0)t/=2,++b1;
			while(t%3==0)t/=3,++b2;
			while(t%5==0)t/=5,++b3;
			while(t%7==0)t/=7,++b4;
			while(t%11==0)t/=11,++b5;
			while(t%13==0)t/=13,++b6;
			for(ri s=1;s<=b1;++s)mt*=2;
			for(ri a1=0;a1<8;++a1){
				for(ri s=1;s<=b2;++s)mt*=3;
				for(ri a2=0;a2<5;++a2){
					for(ri s=1;s<=b3;++s)mt*=5;
					for(ri a3=0;a3<4;++a3){
						for(ri s=1;s<=b4;++s)mt*=7;
						for(ri a4=0;a4<3;++a4){
							for(ri s=1;s<=b5;++s)mt*=11;
							for(ri a5=0;a5<3;++a5){
								for(ri s=1;s<=b6;++s)mt*=13;
								for(ri a6=0;a6<3;++a6){
									Add(g[max(a1,b1)][max(a2,b2)][max(a3,b3)][max(a4,b4)][max(a5,b5)][max(a6,b6)],mul(f[a1][a2][a3][a4][a5][a6],mul(mt,pri[i])));
									Add(g[max(a1,b1)][max(a2,b2)][max(a3,b3)][max(a4,b4)][max(a5,b5)][max(a6,b6)],mul(ss[a1][a2][a3][a4][a5][a6],mt));
									if(a6<b6)mt/=13;
								}
								if(a5<b5)mt/=11;
							}
							if(a4<b4)mt/=7;
						}
						if(a3<b3)mt/=5;
					}
					if(a2<b2)mt/=3;
				}
				if(a1<b1)mt/=2;
			}
			for(ri a1=0;a1<8;++a1)for(ri a2=0;a2<5;++a2)for(ri a3=0;a3<4;++a3)
			for(ri a4=0;a4<3;++a4)for(ri a5=0;a5<3;++a5)for(ri a6=0;a6<3;++a6)
			Add(ss[a1][a2][a3][a4][a5][a6],g[a1][a2][a3][a4][a5][a6]);
		}
		for(ri a1=0;a1<8;++a1)for(ri a2=0;a2<5;++a2)for(ri a3=0;a3<4;++a3)
		for(ri a4=0;a4<3;++a4)for(ri a5=0;a5<3;++a5)for(ri a6=0;a6<3;++a6)
		Add(res,ss[a1][a2][a3][a4][a5][a6]),Add(f[a1][a2][a3][a4][a5][a6],ss[a1][a2][a3][a4][a5][a6]);
	}
	cout<<res;
	return 0;
}

B

线性基入门题,对于每个点,把其权值看做属性 A A A ,把连向它的边的边权异或和看做属性 B B B ,然后对属性 B B B 做以属性 A A A 为第一关键字的线性基即可
CODE:

#include
#define ri register int
#define fi first
#define se second
#define pb push_back
#define rsz resize
#define sz(x) (int)(x).size()
#define lb lower_bound
#define rb upper_bound
#define all(x) (x).begin(),(x).end()
using namespace std;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
typedef long long ll;
typedef pair<ll,ll> pll;
inline ll readl(){
	ll ans=0;
	bool f=1;
	char ch=gc();
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return f?ans:-ans;
}
const ll inf=1e18;
const int N=1e5+5;
int n,m;
ll a[N],Vl[N],bas[N],all=0;
pll vl[N];
int main(){
	n=read(),m=read();
	ll w;
	for(ri i=1;i<=n;++i)Vl[i]=readl(),all+=Vl[i];
	for(ri u,v,i=1;i<=m;++i){
		u=read(),v=read(),w=readl();
		a[u]^=w,a[v]^=w;
	}
	for(ri i=1;i<=n;++i)vl[i]=pll(Vl[i],a[i]);
	sort(vl+1,vl+n+1);
	ll ans=0;
	for(ri i=n;i;--i){
		for(ri j=62;~j;--j){
			if(vl[i].se>>j&1){
				if(!bas[j]){ans+=vl[i].fi,bas[j]=vl[i].se;break;}
				else vl[i].se^=bas[j];
			}
			if(!vl[i].se)break;
		}
	}
	cout<<ans*2-all;
	return 0;
}


C

zxytxdy!

考虑转化题意,按照如下的方式构建思维模型:
现在平面上有 n n n 个点 ( x i , y i ) (x_i,y_i) (xi,yi) ,保证对于任意时刻满足 x i > 0 , y i > 0 , ∀ i ≠ j , x i ≠ x j & & y i ≠ y j x_i>0,y_i>0,\forall i\not=j,x_i\not=x_j\&\&y_i\not=y_j xi>0,yi>0,i=j,xi=xj&&yi=yj ,且每过一个时刻每个点向右平移一个单位,要求支持删掉一个点 i : ( x i y i ≤ 10 ) i:(x_iy_i\le10) i:(xiyi10) 或者插入一个点 i : ( x i ≤ 10 , y i ) i:(x_i\le10,y_i) i:(xi10,yi) ,询问每次操作结束后的二维偏序最长链
这样的话做法就很显然了:
对于 x , y x,y x,y 这两维分别维护一个下标递增的序列 f f f f i f_i fi 表示以 x / y x/y x/y 坐标为 i i i 的点作为起点的二维偏序最长链长度,然后每次插入或删除一个点的时候为了保证两维都递增,考虑先消除 x / y x/y x/y 坐标小于它的点,然后插入/删除,这个时候由于在 f f f 序列中的点满足两维偏序关系,因此可以直接取一个后缀 m a x max max 得到新的答案
至于某一维有哪些点比它小可以对 x , y x,y x,y 两维分别用一个 s e t set set 来维护
复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn) 乘上一个10的中等常数
CODE:

#include
#define ri register int
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef vector<int> poly;
const int rlen=1<<18|1;
char buf[rlen],*ib=buf,*ob=buf;
#define gc() (((ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin)),ib==ob)?-1:*ib++)
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
typedef pair<int,int> pii;
const int N=1e5+15;
int n,m;
struct sgt{
	#define lc (p<<1)
	#define rc (p<<1|1)
	#define mid (l+r>>1)
	int mx[N<<2];
	inline void pushup(int p){mx[p]=max(mx[lc],mx[rc]);}
	inline void update(int p,int l,int r,int k,int v){
		if(l==r){mx[p]=v;return;}
		k<=mid?update(lc,l,mid,k,v):update(rc,mid+1,r,k,v);
		pushup(p);
	}
	inline int query(int p,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return mx[p];
		if(qr<=mid)return query(lc,l,mid,ql,qr);
		if(ql>mid)return query(rc,mid+1,r,ql,qr);
		return max(query(lc,l,mid,ql,qr),query(rc,mid+1,r,ql,qr));
	}
	#undef lc
	#undef rc
	#undef mid
}t1,t2;
typedef set<pii>::iterator It;
struct cp1{inline bool operator()(pii a,pii b){return a.fi<b.fi;}};
struct cp2{inline bool operator()(pii a,pii b){return a.se<b.se;}};
set<pii,cp1>S1;
set<pii,cp2>S2;
int lm1,lm2;
inline void insert(int ps,int vl){
	vector<pii>t;
	S1.insert(pii(ps,vl));
	It it=S2.insert(pii(ps,vl)).fi;
	while(1){
		t.pb(*it);
		t1.update(1,1,lm1,it->fi,0);
		if(it==S2.begin())break;
		--it;
	}
	for(ri upd,i=0;i<t.size();++i){
		upd=t1.query(1,1,lm1,t[i].fi,lm1)+1;
		t1.update(1,1,lm1,t[i].fi,upd);
		t2.update(1,1,lm2,t[i].se,upd);
	}
	cout<<t1.mx[1]<<'\n';
}
inline void delet(int ps){
	vector<pii>t;
	It it=S1.begin();
	while(--ps)t2.update(1,1,lm2,it->se,0),t.pb(*it),++it;
	t1.update(1,1,lm1,it->fi,0);
	t2.update(1,1,lm2,it->se,0);
	S1.erase(*it),S2.erase(*it);
	for(ri upd,i=t.size()-1;~i;--i){
		upd=t2.query(1,1,lm2,t[i].se,lm2)+1;
		t1.update(1,1,lm1,t[i].fi,upd);
		t2.update(1,1,lm2,t[i].se,upd);
	}
	cout<<t2.mx[1]<<'\n';
}
int main(){
	#ifdef ldxcaicai
	freopen("lx.in","r",stdin);
	#endif
	n=read(),m=read();
	lm1=n,lm2=m+10;
	for(ri op,x,y;m;--m){
		op=read();
		if(op==1){
			x=read(),y=read()+m;
			insert(x,y);
		}
		else delet(read());
	}
	return 0;
}

你可能感兴趣的:(#,题解)