Educational Codeforces Round 106 (Rated for Div. 2)ABCD题解

A题,按照题意判断一下就行了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int t,n,m,a[N],b[N];
bool vis[N];
int main()
{
    
    
	scanf("%d",&t);
	while(t--)
	{
    
    
		int k1,k2,w,b;
		scanf("%d%d%d%d%d",&n,&k1,&k2,&w,&b);
		int kmi=min(k1,k2),kma=max(k1,k2);
		if(kmi+(kma-kmi)/2>=w&&(n-kma)+(kma-kmi)/2>=b)puts("YES");
		else puts("NO");		
	}
	return 0;
}

B题,看能不能把字符串变成前面是0后面是1,但是不能同时改变相邻的2个

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int t,n,m,a[N],b[N];
bool vis[N];
string s;
int main()
{
    
    
	scanf("%d",&t);
	while(t--)
	{
    
    
		cin>>s;
		int n=s.size();
		bool f=0;
		for(int i=0;i<n;i++)
		{
    
    
			if(!f&&s[i]=='1')
			{
    
    
				s[i]='0';
				if(s[i+1]=='1')f=1;
				i++;
			}
			else if(f&&s[i]=='0')
			{
    
    
				s[i]='1';
				i++;
			}
		}
		bool ff=0;
		for(int i=1;i<n;i++)if(s[i]-s[i-1]<0)
		{
    
    
			ff=1;
			break;
		}
		if(ff)puts("NO");
		else puts("YES");
	}
	return 0;
}

C题,把奇数位当作是往右走,把偶数位当作往上走
最优解的情况一定是把最多的步数放再最小段上,其他段只走一步
预处理 s u m a suma suma,和 s u m b sumb sumb,然后遍历更新 a n s ans ans,在最后遍历出最小花费

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int t,n,m;
ll a[N],b[N],ans[N],suma[N],sumb[N];
int main()
{
    
    
	scanf("%d",&t);
	while(t--)
	{
    
    
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
    
    
			ll x;
			scanf("%lld",&x);
			if(i&1)a[i]=x,suma[i]=suma[i-1]+x,sumb[i]=sumb[i-1];
			else b[i]=x,sumb[i]=sumb[i-1]+x,suma[i]=suma[i-1];
		}
		ans[2]=a[1]*n+b[2]*n;
		ll ma=a[1],mb=b[2];
		for(int i=3;i<=n;i++)
		{
    
    
			if(i&1)
			{
    
    
				ll k=i/2;
				if(a[i]<ma)ans[i]=ans[i-1]-(n-k)*(ma-a[i]);
				else ans[i]=ans[i-1]-ma+a[i];
			}
			else
			{
    
    
				ll k=(i-1)/2;
				if(b[i]<mb)ans[i]=ans[i-1]-(n-k)*(mb-b[i]);
				else ans[i]=ans[i-1]-mb+b[i];
			}
			if(i&1)ma=min(ma,a[i]);
			else mb=min(mb,b[i]);
		}
		ll res=(1ll<<60);
		for(int i=2;i<=n;i++)
		res=min(res,ans[i]);
		cout<<res<<'\n';
	}
	return 0;
}

D题,首先要知道 l c m ( a , b ) lcm(a,b) lcm(a,b)= a ∗ b / g c d ( a , b ) a*b/gcd(a,b) ab/gcd(a,b),下面用 g g g表示 g c d ( a , b ) gcd(a,b) gcd(a,b)
即求 a ∗ b ∗ c / g − d ∗ g = x a*b*c/g-d*g=x abc/gdg=x ,而 a a a可以表示成 g ∗ k 1 g*k1 gk1 b b b可以表示成 g ∗ k 2 g*k2 gk2,其中 k 1 k1 k1 k 2 k2 k2互质。
用令 k = k 1 ∗ k 2 k=k1*k2 k=k1k2,那么上式就变成了 g ∗ ( k ∗ c − d ) = x g*(k*c-d)=x g(kcd)=x,那么 k = ( x / g + d ) / c k=(x/g+d)/c k=(x/g+d)/c,其中 x x x % g = 0 g=0 g=0 ( x / g + d ) (x/g+d) (x/g+d)% c = 0 c=0 c=0,这题就变成了求有多少 ( k 1 , k 2 ) (k1,k2) (k1,k2)对,因为 k k k是2个互质的数的乘积,那么就需要知道 k k k有多少个质因子。
比如 k = 2 ∗ 2 ∗ 3 ∗ 5 k=2*2*3*5 k=2235,有3个质因子 ( k 1 , k 2 ) (k1,k2) (k1,k2)可以为 ( 1 , 2 ∗ 2 ∗ 3 ∗ 5 ) (1,2*2*3*5) (1,2235), ( 2 ∗ 2 , 3 ∗ 5 ) (2*2,3*5) (22,35), ( 3 , 2 ∗ 2 ∗ 5 ) . . . . (3,2*2*5).... (3,225)....
不难发现规律, ( k 1 , k 2 ) (k1,k2) (k1,k2)的组数为 C ( 3 , 0 ) + C ( 3 , 1 ) + C ( 3 , 2 ) + C ( 3 , 3 ) = 2 3 C(3,0)+C(3,1)+C(3,2)+C(3,3)=2^3 C(3,0)+C(3,1)+C(3,2)+C(3,3)=23

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e7+10;//k1*k2的最大值为2e7
int prim[N],cnt[N],cc;//cnt[i]表示i这个数有多少个质因子
bool vis[N];
ll ans=0;
int c,d,x;
void init(int n){
    
    
	for(int i=2;i<=n;i++)
	{
    
    
		if(!vis[i])prim[++cc]=i,cnt[i]=1;
		for(int j=1;prim[j]<=n/i;j++)
		{
    
    
			vis[i*prim[j]]=1;
			if(i%prim[j]==0)//如果i含有prim[j]这个因子
			{
    
    
				cnt[i*prim[j]]=cnt[i];
				break;
			}
			else cnt[i*prim[j]]=cnt[i]+1;
		}
	}
}
void work(int k)
{
    
    
	if(((x/k)+d)%c)return;
	int p=((x/k)+d)/c;
	ans+=1<<cnt[p];
}
int main()
{
    
    
	int t;
	scanf("%d",&t);
	init(N-1);
	while(t--)
	{
    
    
		ans=0;
		scanf("%d%d%d",&c,&d,&x);
		for(int i=1;i*i<=x;i++)
		{
    
    
			if(x%i==0)
			{
    
    
				work(i);
				if(i*i!=x)work(x/i);
			}
		}
		cout<<ans<<'\n';
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_46001550/article/details/115005136