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 ",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 ",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 ",ans); return 0; }
D - RGB Triplets
题意:给一个长度为N的字符串S,只包含'R','B','G'。求有多少个三元组$(i,j,k)(1 leq i <j<k leq N)$满足$S_{i} eq S_{j},S_{i} eq S_{k},S_{j} eq S_{k}, j-i eq k-j$。
数据范围:$1leq N leq 4000$
题解:先将满足$S_{i} eq S_{j},S_{i} eq S_{k},S_{j} eq 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 ",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} floor} sum_{a_{2}=1}^{lfloor frac{K}{i} floor}...sum_{a_{N}=1}^{lfloor frac{K}{i} floor} i[gcd(a_{1},a_{2},...,a_{N})==1]$
$=sum_{i=1}^{K}sum_{a_{1}=1}^{lfloor frac{K}{i} floor} sum_{a_{2}=1}^{lfloor frac{K}{i} floor}...sum_{a_{N}=1}^{lfloor frac{K}{i} floor} i sum_{d=1}^{lfloor frac{K}{i} floor} mu(d) lfloor frac{d}{a_{1}} floor lfloor frac{d}{a_{2}} floor ... lfloor frac{d}{a_{N}} floor$
$=sum_{i=1}^{K} i sum_{d=1}^{lfloor frac{K}{i} floor} mu(d) sum_{a_{1}=1}^{lfloor frac{K}{id} floor} sum_{a_{2}=1}^{lfloor frac{K}{id} floor}...sum_{a_{N}=1}^{lfloor frac{K}{id} floor} 1$
$=sum_{i=1}^{K} i sum_{d=1}^{lfloor frac{K}{i} floor} mu(d) lfloor frac{K}{id} floor^{N}$
$=sum_{T=1}^{K} lfloor frac{K}{T} floor^{N} sum_{d|T} mu(d) ast {lfloor frac{T}{d} floor} (T=id)$
$=sum_{T=1}^{K} lfloor frac{K}{T} floor^{N} phi(T)$
由于K不大,预处理欧拉函数,直接遍历即可。K大的话,整除分块加杜教筛(雾。
做法1.看了下官方题解:定义f[i]代表gcd为i的个数,递推关系式:$f[i]={lfloor frac{K}{i} floor}^{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 ",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 ",ans); return 0; }
F - Select Half
题意:给一个长度为N的序列A,要求选$lfloor frac{N}{2} floor$个数,且下标互不相邻,最大化它们的总和。
数据范围:$2 leq N leq 2 imes 10^{5}$
题解:对于选的数的下标,$B_{1},B_{2}....,B_{lfloor frac{N}{2} floor}$,可以发现$sum _{i=2}^{lfloor frac{N}{2} floor}B_{i}-B_{i-1}-2 leq 2$。
因此定义f[i][j]代表选第1~i里面的数(必选第个i数),前面多空了j的最大值。
$left{
egin{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}
ight. $

#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 ",ans); return 0; }