题目
比赛的时候读懂了题目,但是不会,硬写会T。果然赛后自己写的就T了,还用了树状数组和快速幂,十分暴力。然后看了大佬的代码,觉得精妙无比。原理是这样,条件是按照输入的顺序,必须有一个1,至少有1个2,必须有1个3。对于每一个1,它后面的2都有选与不选两种可能,且相互独立。但是我们还需要记录1的个数,或者说是都不选的情况的个数。所以对于每一个3,就用当前的情况数减去1的个数。
#include <bits/stdc++.h>
using namespace std;
#define T int T; scanf("%d", &T); while(T--)
#define lowbit(i) ((i)&(-i))
typedef long long ll;
const int mod=1e9+7;
int main()
{
int n, a, cnt=0, res=0, ans=0;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a);
if(a==1){
res+=1;
res%=mod;
cnt+=1;
} else if(a==2){
res*=2;
res%=mod;
} else if(a==3){
ans+=res-cnt;
ans%=mod;
}
}
printf("%d\n", ans);
return 0;
}
顺便复习一下快速幂的写法
ll binaryPow(ll a, ll b){
ll ans=1;
while(b){
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
这里贴一份第二次补题时写的代码,这份代码会T。但是通过这道题,发现1和3之间的2的个数为 n n n。这样的组合有 2 n − 1 2^{n}-1 2n−1种,而且上一份代码将1d的个数转化为这个-1的数量。而对于1和3就是单纯地累积,也就是影响 2 n − 1 2^{n-1} 2n−1前面的系数。
#include <bits/stdc++.h>
using namespace std;
#define T int T; scanf("%d", &T); while(T--)
typedef long long ll;
const ll mod=1e9+7;
const int N=1e6+10;
ll sum=0, b1[N];
int main()
{
memset(b1, 0, sizeof b1);
int n, b, cnt=0;
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%d", &b);
if(b==1){
b1[cnt++]=1;
} else if(b==2){
for(int j=0; j<cnt; j++){
b1[j]<<=1;
b1[j]%=mod;
}
} else {
for(int j=0; j<cnt; j++){
sum+=(b1[j]-1);
sum%=mod;
}
}
}
printf("%lld\n", sum);
return 0;
}