Codeforces Round #725 (Div. 3)

Codeforces Round #725 (Div. 3)


A. Stone Game(题目

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

分析:

  1. 我们可以很轻松地利用快排知道 a m a x , a m i n a_{max},a_{min} amax,amin的位置,那么其实就变成了删掉 a m a x , a m i n a_{max},a_{min} amax,amin这两个位置,那么其实与他们的数值无关,于是我们设 a m i n a_{min} amin的位置在 x x x a m a x a_{max} amax的位置在 y y y
  2. 于是我们就可以假设这个数列为 S 1 x S 2 y S 3 S_1xS_2yS_3 S1xS2yS3 S 1 , S , 2 , S 3 为 字 符 串 S_1,S_,2,S_3为字符串 S1,S,2,S3),那么就只有三种删法了①删掉 S 1 , S 2 S_1,S_2 S1,S2②删掉 S 1 , S 3 S_1,S_3 S1,S3③删掉 S 2 , S 3 S_2,S_3 S2,S3,只要比较 S 1 + S 2 , S 1 + S 3 , S 2 + S 3 S_1+S_2,S_1+S_3,S_2+S_3 S1+S2,S1+S3,S2+S3的大小,取最小值即可
  3. 我们有知道 x , y x,y x,y的位置和字符串的总长,可轻松求出 S 1 . l e n g t h ( ) = x − 1 , S 2 . l e n g t h ( ) = y − x − 1 , S 3 . l e n g t h ( ) = n − y S_1.length()=x-1,S_2.length()=y-x-1,S_3.length()=n-y S1.length()=x1,S2.length()=yx1,S3.length()=ny

代码实现

#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 n个数,要将其分成 n n n个相等的数,问最少要将多少个数减少,如果不可能输出 − 1 -1 1

分析:

  1. 首先判断不可能的情况,就是 ( ∑ i = 1 n a i )   m o d   n ≠ 0 (\sum_{i=1}^{n}a_i) \bmod n\not=0 (i=1nai)modn=0,直接输出 − 1 -1 1
  2. 之后我们发现只有大于总和的平均数 x ˉ \bar{x} xˉ的才需要将它的量分配给别人,直接 O ( n ) O(n) 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 n n个数,以及 l , r l,r l,r,寻找两个 a i , a j a_i,a_j ai,aj,使得 l ⩽ a i + a j ⩽ r l \leqslant a_i+a_j \leqslant r lai+ajr i , j 与 j , i 算 一 种 i,j与j,i算一种 i,jj,i

分析:

  1. 看到寻找一个值在一个范围里面,容易想到将 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an排序,使得它们有单调性
  2. 于是我们就可以从 i + 1 i+1 i+1~ n n n中寻找符合条件的,但是时间不允许,因为是在一个有这单调性的区间里寻找符合条件的,于是我们就想到了二分,吧 l , r l,r l,r分成两个来做, s t st st表示 a i + a s t ⩾ l a_i+a_st \geqslant l ai+astl s t st st是最小的, e d ed ed表示 a i + a s t ⩽ r a_i+a_st \leqslant r ai+astr e d ed ed是最大的,由单调性可以知道答案就为 ∑ i = 1 n − 1 e d − s t + 1 \sum_{i=1}^{n-1}ed-st+1 i=1n1edst+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,b a,b,每次可以将 a / c a/c a/c或者 b / c b/c b/c c   m o d   a = 0 或 c   m o d   b = 0 c \bmod a=0 或 c \bmod b=0 cmoda=0cmodb=0而且 c > 1 c>1 c>1),问能否操作 k k k次,使得 a = b a=b a=b(不能多,也不能少,只能是 k k k次)

分析:

  1. 明显可以感觉出来,当 k ⩾ 2 k \geqslant 2 k2时,肯定都是可以变成的,但关键在于能不能变 k k k次,应为是整除,所以每次都至少要除以一个 a 或 b a或b ab的质因数吧,所以说利用分解质因数得到 a a a的质因数个数 x x x,同理得到 b b b的质因数个数 y y y,如果 k ⩽ x + y k \leqslant x+y kx+y就是可行的,否则不可以
  2. 那么关于 k = 1 k=1 k=1的情况,其实只要 a , b a,b 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 : = h a h a h a := hahah a=hahah为令 a a a这个字符串的值变为 h a h a h hahah hahah a = b + c a = b + c a=b+c a a a的值为 b b b c c c拼接在一起,问最后一次操作的 a a a中,有多少个 h a h a haha haha

分析:傻题,利用 m a p , s t r i n g map,string 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 a a~ b b b,每次操作将 a + 1 a+1 a+1,直到 a = b a=b a=b,问总共的数字变化次数

分析:

  1. s u m a suma suma为从 0 0 0~ a a a的变化次数, s u m b sumb sumb同理,则明显的,答案就为 s u m b − s u m a sumb-suma sumbsuma
  2. 我们发现从 0 0 0~ a a a,每增加 1 1 1个位变一次,每增加 10 10 10十位变一次,每增加 100 100 100百位变一次……所以我们就知道 s u m a = ∑ i = 1 log ⁡ 10 a a / 1 0 i suma=\sum_{i=1}^{\log_{10}a}a/10^i suma=i=1log10aa/10i

代码实现:

#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,y x,y,每次将 x − a , y − b x-a,y-b xa,yb x − b , y − a x-b,y-a xb,ya,问最多能减多少次

分析:

  1. x − a , y − b x-a,y-b xa,yb q q q次, x − b , y − a x-b,y-a xb,ya p p p次,根据题目有 { q ∗ a + p ∗ b ≤ x q ∗ b + p ∗ a ≤ y \begin{cases} q*a+p*b \leq x\\ q*b+p*a \leq y\\ \end{cases} {qa+pbxqb+pay两式相加 q ∗ ( a + b ) + p ∗ ( a + b ) ≤ x + y q*(a+b)+p*(a+b) \leq x+y q(a+b)+p(a+b)x+y q + p ≤ a + b x + y q+p \leq \frac{a+b}{x+y} q+px+ya+b那我们回过头来看看 q , p q,p q,p的定义,就知道 q + p q+p q+p就是我们要求的答案了
  2. 但是它不一定能取到最大值,根据 q + p q+p q+p有单调性,我们可以想到用二分,但怎么判断它可以成立呢,这里先令 a ≥ b a \geq b ab,则 m i d = ( l + r ) / 2 mid=(l+r)/2 mid=(l+r)/2,所以 p = m i d − q p=mid-q p=midq,将上个不等式组带入 { q ∗ a + ( m i d − q ) ∗ b ≤ x q ∗ b + ( m i d − q ) ∗ a ≤ y \begin{cases} q*a+(mid-q)*b \leq x\\ q*b+(mid-q)*a \leq y\\ \end{cases} {qa+(midq)bxqb+(midq)ay { q ∗ ( a − b ) ≤ x − b ∗ m i d q ∗ ( b − a ) ≤ y − a ∗ m i d \begin{cases} q*(a-b) \leq x-b*mid \\ q*(b-a) \leq y-a*mid \end{cases} {q(ab)xbmidq(ba)yamid { q ≤ x − b ∗ m i d a − b q ≥ y − a ∗ m i d b − a \begin{cases} q \leq \frac{x-b*mid}{a-b} \\ q \geq \frac{y-a*mid}{b-a} \end{cases} {qabxbmidqbayamid于是就变成了找是否存在自然数 q q 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值