牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
B 智乃酱的子集与超集
二进制状态压缩
1011 表示选取 1,2,4 号物品的状态
先求出每种状态对应的价值(即集合内所有数的异或和)
下面的思路比较难想:
枚举每个物品,枚举每种状态,对于某状态如果存在这个物品,那么这个状态去掉当前物品一定是它的子集,son[Case] (即所有子集的价值和) 累加该子集的son[Case'] ,如果不存在这个物品,那当前状态加上这个物品就一定是它的超集,chao[Case] (即所有超集的价值和) 累加该超级的chao[Case']
用这种策略可以不重复的累加每个状态的所有子集与超集的价值(可以好好思考一下)
启发
如果题目中出现集合,子集等概念,可考虑二进制状态压缩,并考虑状态之间的关联、关系。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll R(){ll a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}return a*b;}
const ll Ma=1<<20;
ll n,m;
ll a[25];
ll son[Ma],chao[Ma];
int main(){
// freopen("R.txt","r",stdin);
n=R();m=R();
for(ll i=0;i<n;++i){
a[i]=R();
}
ll Max_case=(1<<n)-1;
for(ll i=0;i<=Max_case;++i){
ll sum=0;
for(ll j=0;j<n;++j){
if((1<<j)&i) sum^=a[j];
}
son[i]=chao[i]=sum;
}
for(ll i=0;i<n;++i){
for(ll j=0;j<=Max_case;++j){
if(j&(1<<i)) son[j]+=son[j^(1<<i)];
else chao[j]+=chao[j^(1<<i)];
}
}
while(m--){
ll cnt=R(),Case=0;
while(cnt--){
ll t=R();
Case |= (1<<(t-1));
}
printf("%lld %lld\n",son[Case],chao[Case]);
}
return 0;
}
F 牛牛的猜球游戏
考虑前缀和的思想,消去L-1次操作以前的影响
先预处理出每一次操作后的状态
然后对第L-1次操作后的状态进行1~N重编码
那么第R次操作后的结果就是当前状态的编码
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int R(){int a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}return a*b;}
int n,m;
int f[100010][10];
int t[10];
int main(){
// freopen("R.txt","r",stdin);
n=R();m=R();
for(int i=0;i<10;++i){
f[0][i]=i;
}
for(int i=1;i<=n;++i){
for(int j=0;j<10;++j){
f[i][j]=f[i-1][j];
}
int a=R(),b=R();
swap(f[i][a],f[i][b]);
}
while(m--){
int l=R(),r=R();
for(int i=0;i<10;++i){
t[f[l-1][i]]=i;
}
for(int i=0;i<10;++i){
printf("%d ",t[f[r][i]]);
}
puts("");
}
return 0;
}
H 小w的糖果
操作1:一次前缀和
操作2:两次前缀和
操作3:三次前缀和之后,ans[i]=sum[i-1]+sum[i]
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int R(){int a=0,b=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')b=-1;c=getchar();}while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}return a*b;}
const int mod=1e9+7;
int sum[3][100010];
int n,m;
void init(){
memset(sum,0,sizeof sum);
}
inline int M(int x){
return x%mod;
}
int main(){
// freopen("R.txt","r",stdin);
int T=R();
while(T--){
init();
n=R();m=R();
while(m--){
int type=R(),pos=R();
sum[type-1][pos]++;
}
for(int i=1;i<=n;++i){
for(int j=0;j<3;++j){
sum[j][i]+=sum[j][i-1];
sum[j][i]%=mod;
}
}
for(int i=1;i<=n;++i){
sum[1][i]+=sum[1][i-1];
sum[2][i]+=sum[2][i-1];
sum[1][i]%=mod;
sum[2][i]%=mod;
}
for(int i=1;i<=n;++i){
sum[2][i]+=sum[2][i-1];
sum[2][i]%=mod;
printf("%d ",M(M(M(sum[0][i]+sum[1][i])+sum[2][i])+sum[2][i-1]));
}
putchar('\n');
}
return 0;
}