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);