ABC 162部分题解

T1

思路: 水题,直接模拟。注意用字符串读入更加方便。

#include <bits/stdc++.h>
#define int long long
using namespace std;

string s;

signed main()
{
	cin>>s;
	if (s[0]=='7'||s[1]=='7'||s[2]=='7')  cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	
	return 0;
} 

T2

思路: 直接模拟即可。注意答案为所有不大于n的无法被3或5整除的数之和,与其他的数(Fizz?Buzz?FizzBuzz?这不是数)无关。

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,ans=0;

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		if (i%3!=0&&i%5!=0)  ans+=i;
	}
	cout<<ans<<endl;
	
	return 0;
}

T3

思路: 还说啥,直接模拟。gcd不用打辗转相除了,直接用个__gcd(a,b)完事。

注意NOIP中千万不要用双下划线的函数,否则CE;一定要打辗转相除,这样还会快一点!

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

int k,ans=0;

int get_gcd(int a,int b)
{
	if (b==0)  return a;
	else return get_gcd(b,a%b);
}

int gcd(int a,int b)
{
	int x=a,y=b;
	return get_gcd(x,y);
}

signed main()
{
	cin>>k;
	for (int i=1;i<=k;i++)
	{
		for (int j=1;j<=k;j++)
		{
			for (int w=1;w<=k;w++)  ans+=gcd(gcd(i,j),w);
		}
	}
	cout<<ans<<endl;
	
	return 0;
}

本蒟蒻觉得这三题是不是太水了些,以后能不能学一学Div.3前三题的难度?

T4

考虑找到满足①的(i,j,k)的数量再减去不满足②但满足①的(i,j,k)的数量。

首先,如何找满足①的(i,j,k)呢? 不妨设i<j<k。首先,前面两重循环枚举i, j的值,然后对于(i,j)查满足要求的k的数量,并发现这一步(查k的数量)可以优化。即,这里满足要求的k的数量为区间[j+1,n]中与Si, Sj均不相同的位置数,可以用后缀和轻松搞定。

然后再算,满足要求①但不满足②的(i,j,k)只有一种情况: Si≠Sj且Sj≠Sk且j-i=k-j。那么,还是一样,两重循环枚举i, j,然后查满足要求的k的值,这里k=j+(j-i)=2j-i。注意不要让k超界。

然后把上面两个答案相减即可。具体操作请见代码。

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,ans=0;
int a[5005],pre[5][5005];

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		char ch;
		cin>>ch;
		
		if (ch=='R')  a[i]=0;
		else if (ch=='G')  a[i]=1;
		else a[i]=2;
	}
	for (int i=n;i>=1;i--)
	{
		pre[a[i]][i]=pre[a[i]][i+1]+1;
		pre[(a[i]+1)%3][i]=pre[(a[i]+1)%3][i+1];
		pre[(a[i]+2)%3][i]=pre[(a[i]+2)%3][i+1];
	}
	for (int i=1;i<=n-2;i++)
	{
		for (int j=i+1;j<=n-1;j++)
		{
			if (a[i]==a[j])  continue;
			
			int pos;
			for (int k=0;k<=2;k++)
			{
				if (k!=a[i]&&k!=a[j])
				{
					pos=k;
					break;
				}
			}
			ans+=pre[pos][j+1];
		}	
	}
	for (int i=1;i<=n-2;i++)
	{
		for (int j=i+1;j<=n-1;j++)
		{
			int pos=2*j-i;
			if (pos>n||pos<=0)  break;
			
			if (a[i]!=a[j]&&a[i]!=a[pos]&&a[j]!=a[pos])  ans--;
		}
	}
	cout<<ans<<endl;
	
	return 0;
}

另外,我们班的一位大佬还有一种思路,就是把R, G, B的位置分别存并枚举R, G的位置,累加此时满足要求的B的位置的数量。个人认为这种做法更好更快,但是更容易写错。

贴上这位大佬的代码:

#include<bits/stdc++.h>
using namespace std;

vector<int> vr,vg,vb;

int main(){
	string s;
	int n;
	long long ans=0;
	cin>>n>>s;
	
	for(int i=0;i<n;i++){
		if(s[i]=='R') vr.push_back(i);
		else if(s[i]=='G') vg.push_back(i);
		else vb.push_back(i);
	}
	
	int a=vr.size(),b=vg.size(),c=vb.size();
	for(int i=0;i<a;i++){
		for(int j=0;j<b;j++){
			ans+=c;
			
			int d=abs(vr[i]-vg[j]);
			int mi=min(vr[i],vg[j]),ma=max(vr[i],vg[j]);
			
			if(mi-d>=0&&s[mi-d]=='B') ans--;
			if(ma+d<n&&s[ma+d]=='B') ans--;
			if((vr[i]+vg[j])%2==0&&s[mi+d/2]=='B') ans--;
		}
	}
	
	cout<<ans;
	return 0;
}

这是最典型的两种做法。本题做法很多,这里不再论述。

T5

赛后轻松AC,赛中脑子瓦特……

思路: 考虑dp 递推

状态设计 d p [ i ] dp[i] 表示最大公约数为i的不同序列的个数。

状态转移的第一部分为 d p [ i ] = [ k / i ] n dp[i]=[k/i]^n ,即 [ k / i ] [k/i] 表示每个数取值的数量(由于最大公约数为i,那么每个数都必须是i的倍数且需要小于等于k,那么每个数就可以取 [ k / i ] [k/i] 种值,其中 [ a / b ] [a/b] 表示 a / b a/b 向下取整的值);由于有n个数,那么根据乘法原理得到 d p [ i ] = [ k / i ] n dp[i]=[k/i]^n 这个显而易见的式子。

接着,相信各位大佬都发现了,如果一个序列的最大公约数为6,那么这种序列会被重复算,即在 d p [ 6 ] dp[6] 算了一次,又在 d p [ 3 ] , d p [ 2 ] , d p [ 1 ] dp[3],dp[2],dp[1] 算了一次。所以得到整个状态转移公式,即 d p [ i ] = [ k / i ] n Σ d p [ t ] dp[i]=[k/i]^n-Σdp[t] ,其中t不等于i,且t为i的倍数, 也需满足 t k t≤k

然后贴上核心代码(状态转移):

for (int i=k;i>=1;i--)
	{
		a[i]=quick_power(k/i,n)%mod;
		for (int j=2*i;j<=k;j+=i)  a[i]=((a[i]-a[j])%mod+mod)%mod;
	}

时间复杂度: O ( ( l o g n + l o g k ) k ) O((logn+logk)k) ,注意这里 l o g log 省略的底数为2。

贴上高清无码 的代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,k,mod=1e9+7,ans=0;
int a[100005];

int quick_power(int a,int b)
{
	int res=1;
	for (;b;b=b>>1,a=(a*a)%mod)
	{
		if (b&1)  res=(res*a)%mod;
	}
	return res;
}

signed main()
{
	cin>>n>>k;
	for (int i=k;i>=1;i--)
	{
		a[i]=quick_power(k/i,n)%mod;
		for (int j=2*i;j<=k;j+=i)  a[i]=((a[i]-a[j])%mod+mod)%mod;
	}
	for (int i=1;i<=k;i++)  ans=(ans+a[i]*i)%mod;
	cout<<ans<<endl;
	
	return 0;
}

T6

待填坑……

总结

①排名: 1544(中国第126)
②总分: 1000

③我还是太弱了……

原创文章 19 获赞 27 访问量 1949

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/105476635
ABC