AtCoder Beginner Contest 162
A - Lucky 7
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { int n; scanf("%d",&n); bool f=false; while(n) { if(n%10==7) f=true; n/=10; } printf("%s\n",f?"Yes":"No"); return 0; }
B - FizzBuzz Sum
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { int n; scanf("%d",&n); ll ans=0; for(int i=1;i<=n;i++) { if(i%3==0||i%5==0) continue; ans+=i; } printf("%lld\n",ans); return 0; }
C - Sum of gcd of Tuples (Easy)
题意:$\sum_{a=1}^{K} \sum_{b=1}^{K} \sum_{c=1}^{K} gcd(a,b,c)$
数据范围:$1 \leq K \leq 200$
题解:K比较小,暴力即可。
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { int n; scanf("%d",&n); ll ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { for(int k=1;k<=n;k++) { ans+=__gcd(__gcd(i,j),k); } } } printf("%lld\n",ans); return 0; }
D - RGB Triplets
题意:给一个长度为N的字符串S,只包含'R','B','G'。求有多少个三元组$(i,j,k)(1 \leq i <j<k \leq N)$满足$S_{i} \neq S_{j},S_{i} \neq S_{k},S_{j} \neq S_{k}, j-i \neq k-j$。
数据范围:$1\leq N \leq 4000$
题解:先将满足$S_{i} \neq S_{j},S_{i} \neq S_{k},S_{j} \neq S_{k}$的算出来,在减去$j-i =k-j$的数目。
总的显然等于num(R)*num(B)*num(G),然后枚举两个端点,判断第三个端点是不是不同于这个两个端点的颜色。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=4e3+5; char s[N]; int main() { int n; scanf("%d%s",&n,s); int a=0,b=0,c=0; for(int i=0;i<n;i++) { if(s[i]=='R') a++; if(s[i]=='G') b++; if(s[i]=='B') c++; } ll ans=1LL*a*b*c; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { if(s[i]==s[j]) continue; if(2*j-i<n&&s[i]!=s[2*j-i]&&s[j]!=s[2*j-i]) ans--; } } printf("%lld\n",ans); return 0; }
E - Sum of gcd of Tuples (Hard)
题意:$\sum_{a_{1}=1}^{K} \sum_{a_{2}=1}^{K}...\sum_{a_{N}=1}^{K} gcd(a_{1},a_{2},...,a_{N})$(mod 1e9+7)
数据范围:$2 \leq N \leq 10^{5},1 \leq K \leq 10^{5}$
题解:
做法0.比赛中写的莫比乌斯反演,化简过程:
$Ans=\sum_{a_{1}=1}^{K} \sum_{a_{2}=1}^{K}...\sum_{a_{N}=1}^{K} gcd(a_{1},a_{2},...,a_{N})$
$=\sum_{i=1}^{K}\sum_{a_{1}=1}^{K} \sum_{a_{2}=1}^{K}...\sum_{a_{N}=1}^{K} i[gcd(a_{1},a_{2},...,a_{N})==i]$
$=\sum_{i=1}^{K}\sum_{a_{1}=1}^{\lfloor \frac{K}{i}\rfloor} \sum_{a_{2}=1}^{\lfloor \frac{K}{i}\rfloor}...\sum_{a_{N}=1}^{\lfloor \frac{K}{i}\rfloor} i[gcd(a_{1},a_{2},...,a_{N})==1]$
$=\sum_{i=1}^{K}\sum_{a_{1}=1}^{\lfloor \frac{K}{i}\rfloor} \sum_{a_{2}=1}^{\lfloor \frac{K}{i}\rfloor}...\sum_{a_{N}=1}^{\lfloor \frac{K}{i}\rfloor} i \sum_{d=1}^{\lfloor \frac{K}{i}\rfloor} \mu(d) \lfloor \frac{d}{a_{1}}\rfloor \lfloor \frac{d}{a_{2}}\rfloor ... \lfloor \frac{d}{a_{N}}\rfloor$
$=\sum_{i=1}^{K} i \sum_{d=1}^{\lfloor \frac{K}{i}\rfloor} \mu(d) \sum_{a_{1}=1}^{\lfloor \frac{K}{id}\rfloor} \sum_{a_{2}=1}^{\lfloor \frac{K}{id}\rfloor}...\sum_{a_{N}=1}^{\lfloor \frac{K}{id}\rfloor} 1$
$=\sum_{i=1}^{K} i \sum_{d=1}^{\lfloor \frac{K}{i}\rfloor} \mu(d) \lfloor \frac{K}{id}\rfloor^{N}$
$=\sum_{T=1}^{K} \lfloor \frac{K}{T}\rfloor^{N} \sum_{d|T} \mu(d) \ast {\lfloor \frac{T}{d}\rfloor} (T=id)$
$=\sum_{T=1}^{K} \lfloor \frac{K}{T}\rfloor^{N} \phi(T)$
由于K不大,预处理欧拉函数,直接遍历即可。K大的话,整除分块加杜教筛(雾。
做法1.看了下官方题解:定义f[i]代表gcd为i的个数,递推关系式:$f[i]={\lfloor \frac{K}{i}\rfloor}^{N}-\sum_{j>i,i|j}f[j]$。
双重循环即可,里面那层循环的复杂度总和是个调和级数,log级别的。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+5; const int MD=1e9+7; int pri[N],tot,phi[N]; bool p[N]; void init() { p[1]=true,phi[1]=1; for(int i=2;i<N;i++) { if(!p[i]) pri[++tot]=i,phi[i]=i-1; for(int j=1;j<=tot&&i*pri[j]<N;j++) { p[i*pri[j]]=true; if(i%pri[j]==0) { phi[i*pri[j]]=phi[i]*pri[j]; break; } else phi[i*pri[j]]=phi[i]*(pri[j]-1); } } } int quick_pow(int x,int y) { int ans=1; while(y) { if(y&1) ans=1LL*ans*x%MD; y>>=1; x=1LL*x*x%MD; } return ans; } void add(int &x,int y) { x+=y; if(x>=MD) x-=MD; } int main() { init(); int n,k,ans=0; scanf("%d%d",&n,&k); for(int i=1;i<=k;i++) { add(ans,1LL*quick_pow(k/i,n)*phi[i]%MD); } printf("%d\n",ans); return 0; }
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+5; const int MD=1e9+7; int f[N]; int quick_pow(int x,int y) { int ans=1; while(y) { if(y&1) ans=1LL*ans*x%MD; y>>=1; x=1LL*x*x%MD; } return ans; } void add(int &x,int y) { x+=y; if(x>=MD) x-=MD; if(x<0) x+=MD; } int main() { int n,k; scanf("%d%d",&n,&k); for(int i=k;i>=1;i--) { f[i]=quick_pow(k/i,n); for(int j=2*i;j<=k;j+=i) { add(f[i],-f[j]); } } int ans=0; for(int i=1;i<=k;i++) { add(ans,1LL*f[i]*i%MD); } printf("%d\n",ans); return 0; }
F - Select Half
题意:给一个长度为N的序列A,要求选$\lfloor \frac{N}{2}\rfloor$个数,且下标互不相邻,最大化它们的总和。
数据范围:$2 \leq N \leq 2 \times 10^{5}$
题解:对于选的数的下标,$B_{1},B_{2}....,B_{\lfloor \frac{N}{2}\rfloor}$,可以发现$\sum _{i=2}^{\lfloor \frac{N}{2}\rfloor}B_{i}-B_{i-1}-2 \leq 2$。
因此定义f[i][j]代表选第1~i里面的数(必选第个i数),前面多空了j的最大值。
$\left\{
\begin{array}{**lr**}
f[i][0]=f[i-2][0]+a[i]\\
f[i][1]=max(f[i-2][1],f[i-3][0])+a[i]\\
f[i][2]=max(f[i-2][2],f[i-3][1],f[i-4][0])+a[i]
\end{array}
\right. $
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+5; int a[N]; ll f[N][3]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { for(int j=0;j<3;j++) { f[i][j]=-1e18; } } for(int i=1;i<=3;i++) { f[i][i-1]=a[i]; } f[3][0]=a[1]+a[3]; for(int i=4;i<=n;i++) { f[i][0]=f[i-2][0]+a[i]; f[i][1]=max(f[i-2][1],f[i-3][0])+a[i]; f[i][2]=max(f[i-2][2],f[i-3][1])+a[i]; if(i>4) f[i][2]=max(f[i][2],f[i-4][0]+a[i]); } ll ans; if(n&1) ans=max(f[n][2],max(f[n-1][1],f[n-2][0])); else ans=max(f[n][1],f[n-1][0]); printf("%lld\n",ans); return 0; }