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;
}
A.cpp

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;
}
B.cpp

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;
}
C.cpp

 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;
}
D.cpp

 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;
}
E_0.cpp
#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;
}
E_1.cpp

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;
}
F.cpp

 

posted @ 2020-04-12 23:24  zdragon  阅读(645)  评论(0编辑  收藏  举报