C. Number of Pairs
这道题大体的题意就是在一个序列中找满足ai+aj在一个范围内的数对。
首先这道题是可以给序列排序的,因为题目中虽然给出i<j的条件,但是原来成立的序对i , j 无论相对顺序如何在新的序列中改变,他们对答案的贡献一定是与原序列一致的。明确这一点之后使用 sort 就可以使得序列有序,有序就具有单调性,就可以使用二分降低时间复杂度。
二分其实要找的就是下标,如图所示:
最外层for循环枚举 ai 的下标,通过二分来找符合条件的 aj (红笔描述的两点性质是二分的依据),这样在这个符合条件的区间里的aj都满足性质,那么区间长度就是对答案的一次贡献。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
long long int a[N];
long long int ll, rr;
int bnri1(long long int l, long long int r, long long int k) {
while(l<r)
{
int mid=l+r+1>>1;
if(a[mid]<k) l=mid;
else r=mid-1;
}
return l;
}
long long int bnri2(long long int l, long long int r, long long int k) {
while(l<r)
{
int mid=l+r+1>>1;
if(a[mid]<=k) l=mid;
else r=mid-1;
}
return l;
}
int main() {
int tt;
cin >> tt;
while (tt--)
{
int n;
cin >> n >> ll >> rr;
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
sort(a+1, a + n+1);
long long int cnt = 0;
for (int i = 1; i <= n; i++)
cnt += bnri2(i, n, rr - a[i]) -bnri1(i , n, ll - a[i]);
cout<<cnt<<endl;
}
return 0;
}
这道题同样可以使用 lower_bound( )和upper_bound( )来实现二分。
一个有序数组中:
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,可以找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,可以找到数字在数组中的下标。
因为地址的线性储存,两段地址做差可以得到区间长度。
F. Interesting Function
题意大概就是从a到b,逐步加1过渡,看b的尾缀改变的个数。看样例即可。
比赛的时候以为是数位DP,然而仔细找一下规律发现并不难。从1到11——改变了12次,其中1~11每个个位数累加对答案贡献了1,十位数过渡的那一次对答案贡献了1,加起来是12。
所以从1到 n 的答案是比较好求的,就是个位,十位,百位…对答案的贡献都是1,所以答案就是各个位数的贡献之和:
while(x)
{
ans+=x;
x/=10;//统计十进制位的个数,每个位对答案都有1:1的贡献
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int get(int x)
{
int ans=0;
while(x)
{
ans+=x;
x/=10;
}
return ans;
}
void solve()
{
int l,r;
cin>>l>>r;
int ans=get(r)-get(l);
cout<<ans<<endl;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
solve();
}
}
D. Another Problem About Dividing Numbers
本题借鉴csdn大佬的题解
本来想的是求约数个数,最后发现约数个数不代表最大步数,还是得求出质因数的个数,逐一削减才可以得到相等的最大步数,最小步数比较好想。
这个最少步数的两次,可以理解为a除以a,b除以b,1=1。最小步数一次可以理解为大的一个数除了__gcd(a,b)。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100;//质数的Max
int st[N], primes[N], idx;
void get_primes()//线性筛筛质数
{ int cnt=0;
for (int i = 2; i <= N; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] <= N / i; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int get(int x)//对筛完的质数分解质因数
{
int t=0;
for(int i=0;primes[i]<=sqrt(x);i++)//因为a,b最大值1e9,开方不超过1e5,所以筛质数筛到 N = 1e5 +10;
{
while(x%primes[i]==0)
{
x/=primes[i];
t++;
}
}
if(x>1) t++;
return t;
}
int main()
{
get_primes();
int t;
scanf("%d", &t);
while(t --)
{
int a, b, k;
long long int l, r = 0;
scanf("%d%d%d", &a, &b, &k);
r += get(a);
r += get(b);
if(a == b) l = 0;
else if(__gcd(a, b) == a || __gcd(a, b) == b) l = 1;
else l = 2;
if(l == 0)
{
if(k <= r && k != 1)
puts("YES");
else puts("NO");
continue;
}
if(k >= l && k <= r)
{
puts("YES");
continue;
}
puts("NO");
}
}