AtCoder Regular Contest 113 A~D题解

2021.2.21

A

题面

较慢但是简单的code

    for(int a=1;a<=k;a++)
	for(int b=1;a*b<=k;b++)
          ans+=floor(k*1.0/a/b);

较快但是很复杂的code(按大小排序剪枝并分类讨论)

        for (i=1;i<=n;i++)
	{
		int tmp=n/i; 
		if (i>tmp) break;
		for (j=i;j<=tmp;j++)
		{
			k=tmp/j;
			if (k<j) break;
			else	if (i==j&&j==k) ans+=1;
			else 	if (i==j&&k>j)  ans+=1+3*(k-j);
			else 	if (j==k) ans+=3;
			else ans+=6*(k-j)+3;
		}
	}

B

题面

因为数据很大,我们需要找一些规律

手推可以发现:(n^m)%10 = n^(m%4+4)%10

至于证明,手推一下个位数的n次方的个位的就好了

        read(a);read(b);read(c);
	c=c%4;
	if (c==0) c=4;
	int mi=1;
	for (i=1;i<=c;i++)
		mi=b*mi%4;
	if (mi==0) mi=4;
	a%=10;
	ans=1;
	for (i=1;i<=mi;i++)
		ans*=a;
	ans%=10;
	printf("%lld",ans); 

C

题面

要求最大值,所以倒序循环找至少连续两个相同的字母,每找到一次就往后覆盖

把在它们后面的与那个字母不相同字母覆修改那个字母

每次只从当前位置循环到上次开始循环的位置

如果当前字母不等于上次外层循环找到的字母,就把上次开始循环的位置以后的字母全部修改成当前字母

因此每个字母被访问2次

时间复杂度O(n)

        scanf("%s",s+1);
	n=strlen(s+1);
	int mx=n;
	char tmp;
	for (i=n;i>=2;i--)
		if (s[i]==s[i-1])
		{ 
			for (j=i;j<mx;j++)	
				if(s[j+1]!=s[i]) ans++; 
			if (s[i]!=tmp) ans+=n-mx;	
			mx=i-2;
			if (mx<=1) break;
			tmp=s[i];
		}
	printf("%lld\n",ans);

D

题面

1 2
1 x a
2 b y

可以用反证法证明这题的结论

我们假设x=a[1],x=b[1],y=a[2],y=b[2]

即x<a<y<b<x

结果不合法

所以不存在两个数同时既是一行中最小的数又是一列中最大的数

所以 Amax <= Bmin

于是得出了一个ans+=( x^n )*( (k-x+1)^m ),1<=x<=k

但是我们发现会重复计算

如A数组和B数组全部是1的情况,不仅在x=1时会记录,x=2,3...时都会记录

所以式子应为ans+=(( x^n )-( (x-1)^n ))*( (k-x+1)^m ),1<=x<=k或者ans+=( x^n )*( (( (k-x+1)^m)-( (k-x)^m )),1<=x<=k

还要特判只有一行或只有一列的情况

        read(n);read(m);read(k);
	if (m==1||n==1)
	{
		if (m>n) n=m,m=1;
		for (x=1;x<=k;x++)
			ans=(ans+(poww(x,n)-poww(x-1,n)+mod)%mod)%mod;
	}
	else
	for (x=1;x<=k;x++)
		ans=(ans+(poww(x,n)-poww(x-1,n)+mod)%mod*poww(k-x+1,m)%mod)%mod;
	printf("%lld\n",ans);
posted @ 2021-02-23 13:01  Ritalc  阅读(100)  评论(0编辑  收藏  举报