Problem - A - Codeforces
题目大意:给定一个数组,你每次可以从左边取一个数字,或者从右边取一个数字,求取得序列中最大值和最小值所需的最小次数.
思路:简单模拟就是了,一共有三种取法,从左向右取完,从右向左取完,两边都取,主要用swap来简化过程.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t, n;
int a[105];
int main(){
cin>>t;
while(t--){
cin>>n;
int mindata = 105, maxdata = 0, minindex = 0, maxindex = 0;
for (int i = 1; i <= n; i++){
cin>>a[i];
if (mindata > a[i]){
mindata = a[i];
minindex = i;
}
if (maxdata < a[i]){
maxdata = a[i];
maxindex = i;
}
}
if (minindex > maxindex)swap(minindex,maxindex);
int left = minindex;
int right = n-maxindex+1;
cout << min(left+right, min(left + maxindex-minindex, right + maxindex-minindex)) <<endl;
}
return 0;
}
Problem - B - Codeforces
题目大意:给定一个序列,你可以选取任意k个元素,将它们的数字个数,任意的分给所有的元素,求出最小的k使得序列的每个数都相等,如果不存在k输出-1.
思路:直接求平均值就可以,当无法被整除的时候,就是无解的情况.大于平均值的数字都会被进行分发.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX = 2e5+5;
ll a[MAX];
int t, n;
long long temp;
int main(){
cin>>t;
while(t--){
cin>>n;
for (int i = 0; i < n; i++){
cin>>a[i];
temp+=a[i];
}
if (temp % n != 0){
cout <<-1 <<endl;
}else{
long long avg = temp / n;
int num = 0;
for (int i = 0; i < n; i++){
if (a[i] >avg){
num++;
}
}
cout << num <<endl;
}
temp = 0;
}
return 0;
}
Problem - C - Codeforces
题目大意:给定一个序列,求出有多少组数对ai, aj满足i < j 且 l <= ai + aj <= r.
思路:读题的时候没看懂,直接跳了,以为是要求满足顺序下的数对个数,直接卡住,后来发现i和j大小关系的限制,只是为了防止数对重复出现一次.比较简单的题目,二分加排序,先把数组排个序,对于序列中的每个数,二分查找l-cur和r-cur+1的边界,两者直接相减就可以得到对于某个数符合的个数.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t, n;
const int MAX = 2e5+5;
ll b[MAX];
ll cal(ll cur){
ll ans = 0;
for (int i = 1; i < n; i++){
int index = lower_bound(b, b+i, cur-b[i]) - b;
if (i > index)ans += (i-index);
}
return ans;
}
int main(){
cin>>t;
while(t--){
long long r, l;
cin>>n>>l>>r;
for (int i = 0; i < n; i++)cin>>b[i];
sort(b, b+n);
cout << cal(l) - cal(r+1) <<endl; //lower_bound查找的包括=的情况,所以在查找右边界的时候要查找>=r+1
}
return 0;
}
Problem - D - Codeforces
题目大意:给定a, b, k三个数,你可以选择任意数n,保证a或者b可以被n整除,然后使a/=n,或b/=n,求能否使用恰好k次操作,使得a=b.
思路:直接求两个数的最大可能的操作数,就是求a,b的质因数个数,如果k大于这个质因数个数,那么无论如何也无法恰好取得k,但如果k<质因数个数,只需要将若干个质因数相乘放在一次操作里,就可以对操作次数进行压缩.题目还需要对k=1的情况进行特判,如果两数相等一定不符合,如果一个数可以被另一个数整除,那么是符合答案的.
这里提一下,想出来了做法还不一定有用,这题时间卡的很紧,因为测试数据量不小,比较好的方式是写一个素数筛,但是如果只筛到1e5, 后面的质数有晒不掉的可能,所以需要特判当前数是否为1,如果不是那么就是质数.反正这道题比较怪,用素数筛需要加特判,如果直接硬枚举得话,时间卡的紧,但是优化优化也能过.
#include<bits/stdc++.h>
using namespace std;
int a, b, k;
int num;
int t;
inline int read(){
int ans = 0;
char last = ' ', ch = getchar();
while(ch<'0'|| ch>'9')last = ch, ch = getchar();
while(ch>='0'&&ch<='9')ans = ans*10+ch-'0', ch = getchar();
if (last == '-')ans=-ans;
return ans;
}
vector<int>prime;
bool isprime[1000005];
int main(){
for (int i = 2; i <= 1000000; ++i){
if (!isprime[i]){
prime.push_back(i);
}
for (int x : prime){
if (x*i > 1000000)break;
isprime[x*i] = true;
if (i % x == 0)break;
}
}
cin>>t;
while(t--){
a=read(), b = read(), k= read();
int temp1 = a, temp2 = b;
num = 0;
for (int i = 0; prime[i] * prime[i] <= a; ++i){
while(a%prime[i]==0){
num++;
a/=prime[i];
}
}
if (a!=1)num++;
for (int i = 0; prime[i] * prime[i] <= b; ++i){
while(b%prime[i]==0){
num++;
b/=prime[i];
}
}
if (b!=1)num++;
if (k < 2){
if ((temp1 % temp2 == 0 ||temp2 % temp1 == 0) && temp1 != temp2){
puts("YES");
}else puts("NO");
}else if (k > num){
puts("NO");
}else puts("YES");
}
return 0;
}
Problem - E - Codeforces
题目大意:模拟题,有两种语句,一种是给定一个变量,对它进行赋值,另一种语句是将两个变量拼接得到第三个变量,求所有变量中包含子串"haha"的个数,每个串只由’h’和’a’组成.
思路:模拟,真的就是模拟,不过直接模拟存不下这么长的字符串,或者你用python写好了交也可以,所以这里需要进行状态压缩,每次拼接只需要保留上次串的前三个和后三个,因为只要拼上一个字符就有可能影响"haha"串的数量,中间的串就可以直接压缩掉,模拟的细节就是需要把几个功能分开写,不然容易出错,(反正我是抄的).
#include<bits/stdc++.h>
using namespace std;
map<string, long long>ans;
long long count(const string& s1, const string& s2){
long long cnt = 0;
for (int i = 0; i + s2.size() <= s1.size(); i++){
if(s1.substr(i, s2.size()) == s2)cnt++;
}
return cnt;
}
string getfirst(const string&s){
if (s.size() <= 3)return s;
return s.substr(0, 3);
}
string getlast(const string&s){
if (s.size() <= 3)return s;
return s.substr(s.size()-3, 3);
}
void solve(){
ans.clear();
map<string, string>ma;
int n;
cin>>n;
long long temp = 0;
while(n--){
string a, b, c, d, e;
cin>>a>>b>>c;
if (b==":="){
ans[a] = count(c, "haha");
ma[a] = c;
}
else{
cin>>d>>e;
string f = ma[c] + ma[e];
ans[a] = ans[c] + ans[e] + count(getlast(ma[c])+getfirst(ma[e]), "haha");
if (f.size() > 6){
f=getfirst(f)+"@"+getlast(f);
}
ma[a]=f;
}
temp = ans[a];
}
cout <<temp <<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
Problem - F - Codeforces
题目大意:给定a和b,求从a增加到b,有多少个字符发生了改变,例如19就改变了8次,910就改变了2次.
思路:其实有点像找规律,从9到10一定是有额外一次,9x到1xx也是有额外一次,也就是说每出现一个10就会额外产生一次,100也是一样,只需要算出a和b分别额外的次数,再一相减就可以得出答案.
#include<bits/stdc++.h>
using namespace std;
long long r, l;
long long MAX = 1000000000;
long long ans;
int t;
int main(){
cin>>t;
while(t--){
cin>>l >> r;
ans = 0;
ans += r-l;
long long temp = MAX;
while(temp > 9){
ans += r/temp;
temp /= 10;
}
temp = MAX;
while(temp > 9){
ans -= l/temp;
temp /= 10;
}
cout <<ans <<endl;
}
return 0;
}
Problem - G - Codeforces
题目大意:给你四个数a和b,还有c和d, 求a和b最多能分成多少组c和d,每次选择数字组成c和d时只能选择a或者选择b,不能混合选.
思路:二分答案+贪心,二分答案还比较好想,因为主要是个解方程的问题,但是具体怎么判断是向左还是向右取边界,就是贪心的思想了,首先,如果cd中较小的那个数满足当前二分出的答案的话,那么就先将a和b都替换成每组c个元素,然后再将若干个c组合并成d组,此时替换过程中求出的就是已满足c的情况下d尽可能大的个数,如果d的个数满足当前二分答案的话直接右移即可.
#include<bits/stdc++.h>
using namespace std;
int t;
long long a, b, c, d;
int main(){
cin>>t;
while(t--){
cin>>a>>b>>c>>d;
if (c > d)swap(c, d);
long long l = 0, r = 2000000001;
while(r - l >1){
long long mid = (l+r)>>1;
bool f = 1;
if (a < mid*c || b < mid*c)f=0;
else{
long long a2 = a-mid*c;
long long b2 = b-mid*c;
if (c == d)f = 1;
else{
long long num = a2 / (d - c) + b2 / (d - c); //将c组进行合并
if (num >= mid)f = 1;
else f = 0;
}
}
if (f)l = mid;
else r = mid;
}
cout << l <<endl;
}
return 0;
}