T1:lcm
求给定的数集的任意非空子集的lcm之和
数集大小2000,元素大小200
要求lcm,那显然唯一分解
然后很容易发现200以内的所有素数中,在某个合数的分解中对应幂次大于1的只有
200
\sqrt{200}
200级别,即
2
,
3
,
5
,
7
,
11
,
13
2,3,5,7,11,13
2,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:咕咕咕