Codeforces Round #725 (Div. 3)

Codeforces Round #725 (Div. 3)


A. Stone Game(题目

题目大意:给你\(n\)个数,\(a_1,a_2...a_n\),要求每次从头或尾删除一个数,直到把\(n\)个数中的最大值和最小值取完,求最少次数。

分析:

  1. 我们可以很轻松地利用快排知道\(a_{max},a_{min}\)的位置,那么其实就变成了删掉\(a_{max},a_{min}\)这两个位置,那么其实与他们的数值无关,于是我们设\(a_{min}\)的位置在\(x\)\(a_{max}\)的位置在\(y\)
  2. 于是我们就可以假设这个数列为\(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\)的大小,取最小值即可
  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\)

分析:

  1. 首先判断不可能的情况,就是\((\sum_{i=1}^{n}a_i) \bmod n\not=0\),直接输出\(-1\)
  2. 之后我们发现只有大于总和的平均数\(\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算一种\)

分析:

  1. 看到寻找一个值在一个范围里面,容易想到将\(a_1,a_2...a_n\)排序,使得它们有单调性
  2. 于是我们就可以从\(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\)次)

分析:

  1. 明显可以感觉出来,当\(k \geqslant 2\)时,肯定都是可以变成的,但关键在于能不能变\(k\)次,应为是整除,所以每次都至少要除以一个\(a或b\)的质因数吧,所以说利用分解质因数得到\(a\)的质因数个数\(x\),同理得到\(b\)的质因数个数\(y\),如果\(k \leqslant x+y\)就是可行的,否则不可以
  2. 那么关于\(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\),问总共的数字变化次数

分析:

  1. \(suma\)为从\(0\)~\(a\)的变化次数,\(sumb\)同理,则明显的,答案就为\(sumb-suma\)
  2. 我们发现从\(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\),问最多能减多少次

分析:

  1. \(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\)就是我们要求的答案了
  2. 但是它不一定能取到最大值,根据\(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;
}

posted @ 2021-10-17 10:29  WBWYX  阅读(41)  评论(0)    收藏  举报