A.最小的数字
思路:
枚举n,n+1,n+2,即可找到符合条件且较小的值
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;
int n,m,k;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
while(1)
{
if(n % 3 == 0)
{
cout << n << '\n';
break;
}
n++;
}
return 0;
}
B.优美的GCD
思路:
构造的一种直接的方法x = n, y = 2 * n。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;
int n,m,k;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tt;
cin >> tt;
while(tt--)
{
cin >> n;
int x, y;
x = n, y = 2 * n;
cout << x << ' ' << y << '\n';
}
return 0;
}
C.优美的序列
思路:
一种猜测,排完序检查每一对是否符合条件,试想一下排完序的序列,如果本来||就很大,那么他们间得距离也尽可能大,如果先将他们放近,就有可能|
|小的反而只能间距很大就不符合要求了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;
int n,m,k;
void solve()
{
cin >> n;
vector<int> a(n);
for(auto &x : a) cin >> x;
sort(a.begin(), a.end());
for(int i = 0;i < n; i++ )
for(int j = i + 1;j < n; j++ )
if(a[j] - a[i] < j - i)
{
cout << -1 << '\n';
return ;
}
for(auto &x : a)
cout << x << ' ';
cout << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
T = 1;
cin >> T;
while(T--) solve();
return 0;
}
D.E Kevin喜欢零
思路:
可以看不懂我的可以去看看牛牛的题解
【题解】牛客小白月赛73_ICPC/CCPC/NOIP/NOI刷题训练题单_牛客竞赛OJ
求某个区间的乘积的数的末尾0的个数,10 = 2 * 5,那么可以提供的末尾0的个数等于min(质因子2的个数,质因子5的个数),我们可以维护两个质因子的前缀和可以在O(1)的计算某个连续子区间乘积的后导零的数量,我们可以枚举右端点r,使用,
分别维护合法的最小边界区间和合法的最大区间边界
例如:n = 5,k = 2,r = 5时,
不能在向右移动,如果在向有移动,区间乘积后导零的个数就小于2了;
不能在向左移动,因为再向左移动,区间乘积后导零个数就大于2了。
对于每个右端点,计算对答案的贡献即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 200010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;
int n,m,k;
ll a[N],a2[N],a5[N];
void solve()
{
cin >> n >> k;
for(int i = 1;i <= n; i++ )
a2[i] = a5[i] = 0;
for(int i = 1;i <= n; i++ )
{
cin >> a[i];
while(a[i] % 2 == 0 && a[i] != 0) a2[i]++, a[i] /= 2;
while(a[i] % 5 == 0 && a[i] != 0) a5[i]++, a[i] /= 5;
}
ll ans = 0;
a2[n+1] = a5[n+1] = 1e18;
for(int i = 1; i<= n; i++ )
{
a2[i] += a2[i - 1];
a5[i] += a5[i - 1];
}
int l = 0, r = 0;
for(int i = 1;i <= n; i ++ )
{
//寻找区间乘积后导零小于k的下标
while(min(a2[i] - a2[r], a5[i] - a5[r]) >= k && r < i) r++;
//寻找区间乘积后导零等于k的第一个下标
while(min(a2[i] - a2[l], a5[i] - a5[l]) > k && l < r) l++;
ans += min(r - l, n);
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
T = 1;
cin >> T;
while(T--) solve();
return 0;
}
二分的做法
枚举左端点,找到第一个符合区间乘积的后导零等于k的位置设它为,还需要找到第一个符合区间乘积的后导零大于k的位置设它为
,那么该端点的贡献值就为
。注意一个点,n这个位置可能取得到,那么设n+1这个位置为无穷大。
#include<bits/stdc++.h>
using namespace std;
const int N = 200010,mod = 1e6+7;
typedef long long ll;
typedef pair<int,int> pii;
int n,m,k;
ll a[N],a2[N],a5[N];
void solve()
{
cin >> n >> k;
for(int i = 1;i <= n; i++ )
a2[i] = a5[i] = 0;
for(int i = 1;i <= n; i++ )
{
cin >> a[i];
while(a[i] % 2 == 0 && a[i] != 0) a2[i]++, a[i] /= 2;
while(a[i] % 5 == 0 && a[i] != 0) a5[i]++, a[i] /= 5;
}
ll ans = 0;
a2[n+1] = a5[n+1] = 1e18;
for(int i = 1; i<= n; i++ )
{
a2[i] += a2[i - 1];
a5[i] += a5[i - 1];
}
a2[n + 1] = 1e9, a5[n + 1] = 1e9; //有可能会跑到r+1,因为n这个位置是有可能符合条件的
for(int i = 1;i <= n; i ++ )
{
int l1,r1,l2,r2;
l1 = i, r1 = n + 1;
while(l1 < r1) //去找第一个符合区间乘积后导零为k的位置
{
int mid = (l1 + r1) / 2;
if(min(a2[mid] - a2[i - 1], a5[mid] - a5[i - 1]) >= k) r1 = mid;
else l1 = mid + 1;
}
l2 = i, r2 = n + 1;
while(l2 < r2) //去找第一个符合区间乘积后导零大于k的位置
{
int mid = (l2 + r2) / 2;
if(min(a2[mid] - a2[i - 1], a5[mid] - a5[i - 1]) > k) r2 = mid;
else l2 = mid + 1;
}
// cout << l1 << ' ' << l2 << endl;
ans += l2 - l1;
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
T = 1;
cin >> T;
while(T--) solve();
return 0;
}