Codeforces Round #725 (Div. 3)
A. Stone Game(题目)
题目大意:给你\(n\)个数,\(a_1,a_2...a_n\),要求每次从头或尾删除一个数,直到把\(n\)个数中的最大值和最小值取完,求最少次数。
分析:
- 我们可以很轻松地利用快排知道\(a_{max},a_{min}\)的位置,那么其实就变成了删掉\(a_{max},a_{min}\)这两个位置,那么其实与他们的数值无关,于是我们设\(a_{min}\)的位置在\(x\),\(a_{max}\)的位置在\(y\)。
- 于是我们就可以假设这个数列为\(S_1xS_2yS_3\)(\(S_1,S_,2,S_3为字符串\)),那么就只有三种删法了①删掉\(S_1,S_2\)②删掉\(S_1,S_3\)③删掉\(S_2,S_3\),只要比较\(S_1+S_2,S_1+S_3,S_2+S_3\)的大小,取最小值即可
- 我们有知道\(x,y\)的位置和字符串的总长,可轻松求出\(S_1.length()=x-1,S_2.length()=y-x-1,S_3.length()=n-y\)
代码实现
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int n;
struct node{ int s,w; }a[110];
bool cmp(node x,node y) { return x.w<y.w; }
int main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
int t;
read(t);
while (t--)
{
int ans=0;
read(n);
for (int i=1;i<=n;i++) read(a[i].w),a[i].s=i;
sort(a+1,a+n+1,cmp);
if (a[1].s>a[n].s) swap(a[1].s,a[n].s);
if (a[1].s<n-a[n].s+1)
{
ans+=a[1].s;
if (n-a[n].s+1<a[n].s-a[1].s)
ans+=n-a[n].s+1;
else
ans+=a[n].s-a[1].s;
}
else
{
ans+=n-a[n].s+1;
if (a[1].s<n-a[1].s+1-(n-a[n].s+1))
ans+=a[1].s;
else
ans+=n-a[1].s+1-(n-a[n].s+1);
}
printf("%d\n",ans);
}
// fclose(stdin);fclose(stdout);
return 0;
}
B. Friends and Candies (题目)
题目大意:给你\(n\)个数,要将其分成\(n\)个相等的数,问最少要将多少个数减少,如果不可能输出\(-1\)
分析:
- 首先判断不可能的情况,就是\((\sum_{i=1}^{n}a_i) \bmod n\not=0\),直接输出\(-1\)
- 之后我们发现只有大于总和的平均数\(\bar{x}\)的才需要将它的量分配给别人,直接\(O(n)\)统计即可
代码实现
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int n,t;
int a[100010*2];
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
read(t);
while (t--)
{
int sum=0,ans=0;
read(n);
for (int i=1;i<=n;i++) read(a[i]),sum+=a[i];
if (sum/n*n!=sum) { printf("-1\n"); continue; }
else
{
for (int i=1;i<=n;i++) if (a[i]>(sum/n)) ans++;
printf("%lld\n",ans);
}
}
// fclose(stdin);fclose(stdout);
return 0;
}
C. Number of Pairs(题目)
题目大意:给出\(n\)个数,以及\(l,r\),寻找两个\(a_i,a_j\),使得\(l \leqslant a_i+a_j \leqslant r\)(\(i,j与j,i算一种\))
分析:
- 看到寻找一个值在一个范围里面,容易想到将\(a_1,a_2...a_n\)排序,使得它们有单调性
- 于是我们就可以从\(i+1\)~\(n\)中寻找符合条件的,但是时间不允许,因为是在一个有这单调性的区间里寻找符合条件的,于是我们就想到了二分,吧\(l,r\)分成两个来做,\(st\)表示\(a_i+a_st \geqslant l\)且\(st\)是最小的,\(ed\)表示\(a_i+a_st \leqslant r\)且\(ed\)是最大的,由单调性可以知道答案就为\(\sum_{i=1}^{n-1}ed-st+1\)
代码实现:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int t,n,l,r;
int a[2*100010];
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
read(t);
while (t--)
{
memset(a,0,sizeof(a));
read(n);read(l),read(r);
for (int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+n+1);
int sum=0;
for (int i=1;i<=n-1;i++)
{
int x=i+1,y=n,mid=(l+r)/2;
while (y-x>1)
{
//printf("xy:%d %d\n",x,y);
mid=(x+y)/2;
if (a[mid]+a[i]>=l)
y=mid;
else
{
if (a[mid]+a[i]<l)
x=mid+1;
}
}
int st=0;if (a[y]+a[i]>=l) st=y; if (a[x]+a[i]>=l) st=x;
x=i+1,y=n,mid=(l+r)/2;
while (y-x>1)
{
//printf("xy:%d %d\n",x,y);
mid=(x+y)/2;
if (a[mid]+a[i]<=r)
x=mid;
else
{
if (a[mid]+a[i]>r)
y=mid-1;
}
}
int ed=0;if (a[x]+a[i]<=r) ed=x; if (a[y]+a[i]<=r) ed=y;
//printf("%d %d\n",st,ed);
if (st!=0 && ed!=0)
sum+=ed-st+1;
}
printf("%lld\n",sum);
}
// fclose(stdin);fclose(stdout);
return 0;
}
D. Another Problem About Dividing Numbers(题目)
题目大意:给出\(a,b\),每次可以将\(a/c\)或者\(b/c\)(\(c \bmod a=0 或 c \bmod b=0\)而且\(c>1\)),问能否操作\(k\)次,使得\(a=b\)(不能多,也不能少,只能是\(k\)次)
分析:
- 明显可以感觉出来,当\(k \geqslant 2\)时,肯定都是可以变成的,但关键在于能不能变\(k\)次,应为是整除,所以每次都至少要除以一个\(a或b\)的质因数吧,所以说利用分解质因数得到\(a\)的质因数个数\(x\),同理得到\(b\)的质因数个数\(y\),如果\(k \leqslant x+y\)就是可行的,否则不可以
- 那么关于\(k=1\)的情况,其实只要\(a,b\)不是倍数关系,就不行,没了。。。😀
代码实现:
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn=4e5+100;
int prime[maxn];
int wyx[maxn];
int wzdsb;
void getPrime()
{
for (int i=2;i<maxn;i++)
{
if (!wyx[i])
{
prime[++wzdsb]=i;
}
for (int j=1;j<=wzdsb && i*prime[j]<maxn;j++)
{
wyx[i*prime[j]]=1;
if (i%prime[j]==0)
break;
}
}
}
int wyxsb(ll x)
{
int sum=0;
for (int i=1;prime[i]*prime[i]<=x;i++)
{
int z=0;
while (x%prime[i]==0)
{
x/=prime[i];
z++;
}
sum+=z;
}
if (x!=1)
sum++;
return sum;
}
int main()
{
getPrime();
int t;
cin >> t;
while (t--)
{
ll a,b,k;
cin >> a >> b >> k;
if (a>b) swap(a,b);
if (k==1)
{
if (b%a!=0||a==b)
cout << "NO" << endl;
else
cout << "YES" << endl;
continue;
}
if (wyxsb(a)+wyxsb(b)>=k)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}
E. Funny Substrings(题目)
题目大意:设\(a := hahah\)为令\(a\)这个字符串的值变为\(hahah\),\(a = b + c\)为\(a\)的值为\(b\)与\(c\)拼接在一起,问最后一次操作的\(a\)中,有多少个\(haha\)
分析:傻题,利用\(map,string\)做即可
代码实现:
#include<bits/stdc++.h>
using namespace std;
struct wyx{
string front;
string back;
long long cnt_haha = 0;
};
wyx haha(const string& s)
{
wyx res;
res.front = s.substr(0, 3);
res.back = s.substr(max(0, (int)s.size() - 3));
for (int i = 0; i < (int)s.size(); i++)
{
if (s.substr(i, 4)=="haha")
{
++res.cnt_haha;
}
}
return res;
}
wyx wbyn(const wyx& a, const wyx& b)
{
wyx res;
res.front = (a.front + b.front).substr(0, 3);
res.back = (a.back + b.back).substr(max(0, (int)a.back.size() + (int)b.back.size() - 3));
res.cnt_haha = a.cnt_haha + b.cnt_haha + haha(a.back + b.front).cnt_haha;
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
map<string, wyx> mp;
for (int i = 0; i < n; i++)
{
string name, op;
cin >> name >> op;
if (op == ":=")
{
string str;
cin >> str;
mp[name] = haha(str);
} else if (op == "=")
{
string a, b;
char ch;
cin >> a >> ch >> b;
mp[name] = wbyn(mp[a], mp[b]);
}
if (i == n - 1)
{
cout << mp[name].cnt_haha << "\n";
}
}
}
return 0;
}
F. Interesting Function(题目)
题目大意:问从\(a\)~\(b\),每次操作将\(a+1\),直到\(a=b\),问总共的数字变化次数
分析:
- 设\(suma\)为从\(0\)~\(a\)的变化次数,\(sumb\)同理,则明显的,答案就为\(sumb-suma\)
- 我们发现从\(0\)~\(a\),每增加\(1\)个位变一次,每增加\(10\)十位变一次,每增加\(100\)百位变一次……所以我们就知道\(suma=\sum_{i=1}^{\log_{10}a}a/10^i\)
代码实现:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int t,a,b;
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
read(t);
while (t--)
{
int suma,sumb;suma=sumb=0;
read(a),read(b);
while (a>0) suma+=a,a/=10;
while (b>0) sumb+=b,b/=10;
printf("%lld\n",sumb-suma);
}
// fclose(stdin);fclose(stdout);
return 0;
}
G. Gift Set(题目)
题目大意:有两个数\(x,y\),每次将\(x-a,y-b\)或\(x-b,y-a\),问最多能减多少次
分析:
- 设\(x-a,y-b\)有\(q\)次,\(x-b,y-a\)有\(p\)次,根据题目有$$\begin{cases} qa+pb \leq x\ qb+pa \leq y\ \end{cases} $$两式相加$$q(a+b)+p(a+b) \leq x+y$$$$q+p \leq \frac{a+b}{x+y}$$那我们回过头来看看\(q,p\)的定义,就知道\(q+p\)就是我们要求的答案了
- 但是它不一定能取到最大值,根据\(q+p\)有单调性,我们可以想到用二分,但怎么判断它可以成立呢,这里先令\(a \geq b\),则\(mid=(l+r)/2\),所以\(p=mid-q\),将上个不等式组带入$$\begin{cases} qa+(mid-q)b \leq x\ qb+(mid-q)a \leq y\ \end{cases}$$ $$\begin{cases} q(a-b) \leq x-bmid \ q(b-a) \leq y-amid \end{cases}$$$$\begin{cases} q \leq \frac{x-bmid}{a-b} \ q \geq \frac{y-amid}{b-a} \end{cases}$$于是就变成了找是否存在自然数\(q\),满足上面的不等式,二分判断即可。
代码实现:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
void read(int &sum)
{
sum=0;char last='w',ch=getchar();
while (ch<'0' || ch>'9') last=ch,ch=getchar();
while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
if (last=='-') sum=-sum;
}
int t;
int x,y,a,b;
int max(int x,int y) { if (x>y) swap(x,y); return y; }
int min(int x,int y) { if (x<y) swap(x,y); return y; }
bool check(int mid)
{
if(b==a)
return mid<=min(x/a,y/b);
int l=(int)ceil(1.0*(y-a*mid)/(b-a));
int r=(int)floor(1.0*(x-b*mid)/(a-b));
l=max(0,l),r=min(r,mid);
if(l<=r) return 1;
else return 0;
}
signed main()
{
// freopen("M.in","r",stdin);
// freopen("M.out","w",stdout);
read(t);
while (t--)
{
cin>>x>>y>>a>>b;
if(a<b) swap(a,b);
int l=0,r=max(x/a,y/b),ans=0;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
cout<<ans<<endl;
}
// fclose(stdin);fclose(stdout);
return 0;
}