190921CSP-S模擬題解

T1:lcm
求給定的數集的任意非空子集的lcm之和
數集大小2000,元素大小200

要求lcm,那顯然唯一分解
然後很容易發現200以內的所有素數中,在某個合數的分解中對應冪次大於1的只有200\sqrt{200}級別,即2,3,5,7,11,132,3,5,7,11,13
所以我們可以把這些素數出現的狀態壓縮一下,然後每個合數除掉這些素數之後剩下的一定只剩下一個素數或者1,那就可以按這個素數分類然後dp就完了

Code:

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define db double
#define se second
#define fi first
#define mod 1000000007
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=2005;
inline int add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int dec(int x,int y){x-=y;if(x<0) x+=mod;return x;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void Dec(int &x,int y){x-=y;if(x<0) x+=mod;}
inline void Mul(int &x,int y){x=mul(x,y);}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a)) if(b&1) res=mul(res,a);return res;}
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],sum[8][5][4][3][3][3];
vector<int>fac[41];
int main(){
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) for(int j=0;j<=41;j++) if(a[i]%pri[j]==0) {a[i]/=pri[j],fac[j].pb(a[i]);break;}
	f[0][0][0][0][0][0]=1;
	int ans=0;
	for(int i=40;~i;i--){
		if(!fac[i].size()) continue;
		memset(sum,0,sizeof(sum));
		for(int j=0;j<fac[i].size();j++){
			memset(g,0,sizeof(g));
			int ml=1,n1=0,n2=0,n3=0,n4=0,n5=0,n6=0;
			int v=fac[i][j];
			while(v%2==0) v/=2,++n1;while(v%3==0) v/=3,++n2;while(v%5==0) v/=5,++n3;while(v%7==0) v/=7,++n4;while(v%11==0) v/=11,++n5;while(v%13==0) v/=13,++n6;
			for(int s=1;s<=n1;s++) ml*=2;
			for(int a1=0;a1<8;a1++){
				for(int s=1;s<=n2;s++)ml*=3;
				
				for(int a2=0;a2<5;a2++){
					for(int s=1;s<=n3;s++)ml*=5;
					
					for(int a3=0;a3<4;a3++){
						
						for(int s=1;s<=n4;s++)ml*=7;
						
						for(int a4=0;a4<3;a4++){
							
							for(int s=1;s<=n5;s++)ml*=11;
							
							for(int a5=0;a5<3;a5++){
								
								for(int s=1;s<=n6;s++)ml*=13;
								
								for(int a6=0;a6<3;a6++){
									int mx1=max(n1,a1),mx2=max(n2,a2),mx3=max(n3,a3),mx4=max(n4,a4),mx5=max(n5,a5),mx6=max(n6,a6);
									inc(g[mx1][mx2][mx3][mx4][mx5][mx6],mul(f[a1][a2][a3][a4][a5][a6],mul(ml,pri[i])));
									inc(g[mx1][mx2][mx3][mx4][mx5][mx6],mul(sum[a1][a2][a3][a4][a5][a6],ml));
									if(a6<n6) ml/=13;
								}
								if(a5<n5) ml/=11;
							}
							if(a4<n4) ml/=7;
						}
						if(a3<n3) ml/=5;
					}
					if(a2<n2) ml/=3;
				}
				if(a1<n1) ml/=2;
			}
			for(int a1=0;a1<8;a1++)
				for(int a2=0;a2<5;a2++)
					for(int a3=0;a3<4;a3++)
						for(int a4=0;a4<3;a4++)
							for(int a5=0;a5<3;a5++)
								for(int a6=0;a6<3;a6++) inc(sum[a1][a2][a3][a4][a5][a6],g[a1][a2][a3][a4][a5][a6]);
		}
		for(int a1=0;a1<8;a1++)
			for(int a2=0;a2<5;a2++)
				for(int a3=0;a3<4;a3++)
					for(int a4=0;a4<3;a4++)
						for(int a5=0;a5<3;a5++)
							for(int a6=0;a6<3;a6++) inc(ans,sum[a1][a2][a3][a4][a5][a6]),inc(f[a1][a2][a3][a4][a5][a6],sum[a1][a2][a3][a4][a5][a6]);
	}
	cout<<ans;
	return 0;
}

T2:Xor
嚴重吐槽題面
“割”這一定義在網絡流中指的是一個邊集,這裏卻指點集,要不你就換個詞描述非得用“
割“嗎

題意:一張無向圖,每個點有點權,每條邊有邊權,對於一個點的集合,若一條邊的兩個端點分別在集合內和集合的補集內,則這個集合的權值會異或上這條邊的邊權
定義一個點集爲合法的當且僅當其任意非空子集的權值不爲0,點集的價值爲點集內的點的點權之和減去點集外的點的點權之和,請求出價值最大的點集的價值

首先異或有一個性質,一個數被相同的數異或兩次其值不變,所以對於任意一個點,我們定義它的權值爲連接它的所有邊的權值的異或和,則一個點集的權值即爲點集內的所有點的權值異或和,那麼要求選一個點集,其任意子集的權值不爲0即是要求裏面所有點線性無關,那麼按照點權排序做線性基即可

Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1e5+5;
struct info{
	ll key,val;
	info(){}
	info(ll _key,ll _val):key(_key),val(_val){}
	inline bool operator < (const info &b){return val>b.val;}
}p[N];
ll sset[N];
int main(){
	int n=read(),m=read();ll sum=0;
	for(int i=1;i<=n;i++) p[i].val=read(),sum+=p[i].val;
	for(int i=1;i<=m;i++){
		int x=read(),y=read();ll z=read();
		p[x].key^=z;p[y].key^=z;
	}
	sort(p+1,p+n+1);
	ll ans=0;
	for(int i=1;i<=n;i++){
		int f=0;
		for(int j=63;~j;j--){
			if(!p[i].key) break;
			if(!(p[i].key>>j)) continue;
			if(!sset[j]) {sset[j]=p[i].key,ans+=p[i].val;f=1;break;}
			else p[i].key^=sset[j];
		}
		if(!f) ans-=p[i].val;
	}
	cout<<ans;
	return 0;
}

T3:咕咕咕

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章