P5390 [Cnoi2019]數學作業(位運算&組合數學)
題意:求給定集合所有子集元素異或和的求和。
思路:考慮每個位上的貢獻次數。
設對於集合,當前位上爲的個數爲,顯然我們需要選出奇數個才能使該位異或爲,其他爲的數可選可不選,方案數爲:,顯然對於個1,選出奇數個1和偶數個方案是一樣的,因爲對於爲奇數,.
偶數同理。
所以選出奇數個方案數爲.
所以對於第位的貢獻是:.
需要注意的是當時是不可能產生貢獻的,所以我們只需要將集合中所有數進行按位或運算,再乘上即可。
時間複雜度:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=998244353;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
inline void read(int &x){
x=0;int w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
for(;ch>='0'&&ch<='9';ch=getchar())
x=(x<<3)+(x<<1)+(ch&15);
x*=w;
}
ll ksm(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
int main(){
int t;
read(t);
while(t--){
int n;
read(n);
int ans=0;
for(reg int i=1;i<=n;i++){
int x;
read(x);
ans=ans|x;
}
ans=1LL*ans*ksm(2,n-1)%mod;
printf("%d\n",ans);
}
return 0;
}