A.
稍加思考就会发现其实只要知道其中非0的不同的数有多少个就可以了。
#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
int main()
{
int n,i,j;
set<int>s;
cin>>n;
for(i=1;i<=n;i++){
cin>>j;
if(j)s.insert(j);
}
cout<<s.size()<<endl;
return 0;
}
B.
记a=GCD*n, b=GCD * m,那么必有LCM=GCD * n * m, 所以可以计算出LCM/GCD,然后枚举这个数的所有分解判断他们是否互质即可。需要注意的是坑爹数据包含了LCM不能整除GCD的情况…
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
int main()
{
int l,r,x,y,i,j,k;
bool issame=false;
cin>>l>>r>>x>>y;
if(y%x){
cout<<0<<endl;return 0;
}
k=y/x;
ll cnt=0;
for(i=1;i*i<=k;i++){
if(k%i==0){
j=k/i;
if(i*x<l||i*x>r||j*x<l||j*x>r)continue;
if(gcd(i,j)!=1)continue;
cnt++;
if(i==j)issame=true;
}
}
cnt*=2;
if(issame)cnt--;
cout<<cnt<<endl;
return 0;
}
C.
题目求的期望值看起来挺麻烦的,但其实50%的几率发生,那么期望值其实就是每次*2-0.5 …,然后最后一次只要 *2即可,我们会发现可以把这个2乘进去,然后这个式子就可以化简为 x *2^(k+1)-(2^k-1),做两次快速幂即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll mod_pow(ll x, ll n, ll mod)
{
ll res = 1;
while (n) {
if (n & 1)
res = res*x%mod;
x = x*x%mod;
n >>= 1;
}
return res;
}
int main()
{
ll x,k,i,j;
cin>>x>>k;
if(!x){
cout<<0<<endl;return 0;
}
x%=mod;
ll res=mod_pow(2,k+1,mod);res=res*x%mod;
ll minus=mod_pow(2,k,mod);minus-=1;
ll ans=(res-minus+mod)%mod;
cout<<ans<<endl;
return 0;
}
D.
题目的做法比较不好描述,大致思想是预处理整个数列,跳过所有那些值为1的数,然后记录每个数的下一个值不为1 的数的位置(数组下标),然后用一个O(n^2)的暴力算法去找这样的序列,因为去除1以后已经优化了很多,所以似乎并不会tle
#include<cstdio>
#include<iostream>
using namespace std;
long long p,s;
int main()
{
int ans=0,n,a[200005],next1[200005],pre,i,j,k;
cin>>n>>k;
for(i=1;i<=n;i++)scanf("%d",&a[i]);
pre=n+1;
for(i=n;i>0;i--) {
next1[i] = pre;
if (a[i] > 1)pre = i;
}
for(i=1;i<=n;i++) {
p = 1;s = 0;
for (j = i; j <= n; j = next1[j]) {
if (a[j] > 2e18/p )break;
p *= a[j];
s += 1LL * k * a[j];
if (p == s)ans++;
if (p > s && (p - s) % k == 0 && (p - s) / k <= next1[j] - j - 1)ans++;
s += 1LL * k * (next1[j] - j - 1);
}
}
printf("%d\n",ans);
return 0;
}