【日记】12.25

自作多情 提交于 2019-12-26 01:09:54

今天写了一天的题,并没有复习。

12.25

DP

1.P1140相似基因:https://www.luogu.com.cn/problem/P1140

思路:dp[i] [j]表示第一个基因的前i位和第二个基因的前j位的最大匹配,则可以从dp[i-1] [j],dp[i-1] [j-1], dp[i] [j-1]三种情况转移过来。只需要关注每次添加的字母是谁就可以了。

#include<bits/stdc++.h>
using namespace std;
const int M=1e2+50;
struct Task{
    int len1,len2,dp[M][M];
    char s1[M],s2[M];
    map<int,int> mp={{'A',1},{'C',2},{'G',3},{'T',4},{'-',5}};
    int tr[6][6]={  {0,0,0,0,0,0},
                    {0,5,-1,-2,-1,-3},
                    {0,-1,5,-3,-2,-4},
                    {0,-2,-3,5,-2,-2},
                    {0,-1,-2,-2,5,-1},
                    {0,-3,-4,-2,-1,0}};
    void init(){
        scanf("%d%s%d%s",&len1,s1+1,&len2,s2+1);
        for(int i=1;i<=len1;++i)
            dp[i][0]=dp[i-1][0]+tr[mp[s1[i]]][mp['-']];
        for(int i=1;i<=len2;++i)
            dp[0][i]=dp[0][i-1]+tr[mp[s2[i]]][mp['-']];
        for(int i=1;i<=len1;++i)
            for(int j=1;j<=len2;++j)
                dp[i][j]=-1e9;
    }
    void run(){
        init();
        for(int i=1;i<=len1;++i)
            for(int j=1;j<=len2;++j)
                dp[i][j]=max(dp[i][j],dp[i-1][j]+tr[mp[s1[i]]][mp['-']]),
                dp[i][j]=max(dp[i][j],dp[i][j-1]+tr[mp[s2[j]]][mp['-']]),
                dp[i][j]=max(dp[i][j],dp[i-1][j-1]+tr[mp[s1[i]]][mp[s2[j]]]);
        printf("%d\n",dp[len1][len2]);
    }
}t;
int main(){
    t.run();
    return 0;
}

数学

1.P2158:洛谷仪仗队

题解:首先可以只观察一半,对第二列,能看到1个,第三列看到2个,实际上就是(3,1)(3,2)这里面两个数互质的个数,所以其实就是phi的前缀和*2+1。

#include<bits/stdc++.h>
using namespace std;
const int M=1e5+20;
#define LL long long
int vis[M],prime[M],cnt;
LL phi[M];
void get(int n){
    phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i])
            prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for(int i=1;i<=n;i++)
        phi[i]+=phi[i-1];
}
int main(){
    int n;
    scanf("%d",&n);
    get(n);
    if (n==1)
        printf("0\n");
    else
        printf("%lld\n",phi[n-1]*2+1);
    return 0;
}

2.P1582

题意:有n个瓶子,每个都有1L水,每次只能选择两个水相同的瓶子,合成一个,扔掉空瓶子。现在需要保留最多k个瓶子,问需要至少购买多少个新的有1L水的新瓶子?

思路:水瓶里的水的体积一定是2的幂,所以n瓶水最少需要的瓶子数,等于n的二进制拆分中1的个数。那么如何减少1的个数呢?答案是需要购买lowbit(n)个新瓶子,然后合成,进位,可能会减少1的数量。

#include<bits/stdc++.h>
using namespace std;
int get_num(int x){
    int ans=0;
    for(int i=0;i<=31;++i)
        ans+=((x>>i)&1);
    return ans;
}
inline int lowbit(int x){return x&-x;}
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    int ans=0;
    while(get_num(n)>k)
        ans+=lowbit(n),n+=lowbit(n);
    printf("%d\n",ans);
    return 0;   
}

分块&&莫反

1.BZOJ1257:计算k%1+k%2+...+k%n的和。1e9。

思路:最简单的分块题目,将取模拆开即可。
\[ \Sigma_{i=1}^{n}k-\lfloor\frac{k}{i}\rfloor*i\\ n*k-\Sigma_{i=1}^{n}i*\lfloor\frac{k}{i}\rfloor \]
这里有个小技巧(学来的:https://blog.csdn.net/qq_42886072/article/details/89408397),特判0和超过n的情况。

#include<bits/stdc++.h>
using namespace std;
struct Task{
    long long ans,n,k;
    void init(){
        scanf("%lld%lld",&n,&k);
    }
    void run(){
        init();
        for(int l=1,r;l<=n;l=r+1)
            r=(k/l?min(n,k/(k/l)):n),ans+=1LL*(l+r)*(r-l+1)/2*(k/l);
        printf("%lld\n",n*k-ans);
    }
}t;
int main(){
    t.run();
    return 0;
}

2.BZOJ2956:求∑∑((n mod i)*(m mod j))其中1<=i<=n,1<=j<=m,i≠j。 mod19940417。

题解:直接两个分别求,然后相乘即可。注意要把i==j的情况减掉!!!

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int P=19940417;
struct Task{
    int n,m;
    void init(){
        scanf("%d%d",&n,&m);
    }
    inline LL sing(int n){return 1LL*n*(n+1)/2%P;}
    LL calc(int k,int n){//计算1-k,n/i的和
        LL ans=0;
        for(int l=1,r;l<=k;l=r+1)
            r=(n/l?min(k,n/(n/l)):k),ans=(ans+(sing(r)-sing(l-1))%P*(n/l)%P)%P;
        return ans;
    }
    inline LL sqr(int n){return (__int128)n*(n+1)*(2*n+1)/6%P;}
    LL cald(int k,int n,int m){
        LL ans=0;
        for(int l=1,r;l<=k;l=r+1)
            r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans=(ans+(sqr(r)-sqr(l-1))%P*(n/l)%P*(m/l)%P)%P;
        return ans;
    }
    void run(){
        init();
        int k=min(n,m);
        printf("%lld\n",((1LL*n*n%P-calc(n,n)+P)%P*(1LL*m*m%P-calc(m,m)+P)%P-(1LL*k*n%P*m%P-m*calc(k,n)%P+P-n*calc(k,m)%P+P+cald(k,n,m))%P+P)%P);
    }
}t;
int main(){
    t.run();
    return 0;
}

莫比乌斯反演

1.BZOJ1101:

#include<bits/stdc++.h>
using namespace std;
const int M=5e4+20;
#define LL long long
LL cnt,phi[M],mu[M],prime[M],vis[M];
void get(int n){
    phi[1]=mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i])
            prime[++cnt]=i,mu[i]=-1,phi[i]=i-1;
        for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            mu[i*prime[j]]=-mu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for(int i=1;i<=n;i++)
        mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
struct Task{
    int d,a,b;
    void init(){
        scanf("%d%d%d",&a,&b,&d);
    }
    LL cald(int k,int n,int m){
        LL ans=0;
        for(int l=1,r;l<=k;l=r+1)
            r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=(mu[r]-mu[l-1])*(n/l)*(m/l);
        return ans;
    }
    void run(){
        init();
        printf("%lld\n",cald(min(a/d,b/d),a/d,b/d));
    }
}t;
int main(){
    get(5e4+2);
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;++i)
        t.run();
    return 0;
}

2.BZOJ2301:

思路:二维前缀和思想,ans=cgcd(b,d,k)-cgcd(a-1,d,k)-cgcd(b,c-1,k)+cgcd(a-1,c-1,k)

#include<bits/stdc++.h>
using namespace std;
const int M=5e4+20;
#define LL long long
int cnt,mu[M],prime[M],vis[M];
void get(int n){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i])
            prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)
        mu[i]+=mu[i-1];
}
struct Task{
    int a,b,c,d,k;
    void init(){
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    }
    LL cald(int k,int n,int m){
        LL ans=0;
        for(int l=1,r;l<=k;l=r+1)
            r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=1LL*(mu[r]-mu[l-1])*(n/l)*(m/l);
        return ans;
    }
    inline LL cgcd(int a,int b,int d){return cald(min(a/d,b/d),a/d,b/d);}//计算i:1-a,j:1-b,gcd=d的数的个数
    void run(){
        init();
        printf("%lld\n",cgcd(b,d,k)-cgcd(a-1,d,k)-cgcd(b,c-1,k)+cgcd(a-1,c-1,k));
    }
}t;
int main(){
    get(5e4+2);
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;++i)
        t.run();
    return 0;
}

3.BZOJ2820:

#include<bits/stdc++.h>
using namespace std;
const int M=1e7+20;
#define LL long long
int cnt,mu[M],prime[M],vis[M];
LL f[M];
void get(int n){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i])
            prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=cnt;++i)
        for(int j=1;j*prime[i]<=n;++j)
            f[j*prime[i]]+=mu[j];
    for(int i=1;i<=n;++i)
        f[i]+=f[i-1];
}
struct Task{
    int n,m;
    void init(){
        scanf("%d%d",&n,&m);
    }
    LL cald(int k,int n,int m){
        LL ans=0;
        for(int l=1,r;l<=k;l=r+1)
            r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=(f[r]-f[l-1])*(n/l)*(m/l);
        return ans;
    }
    void run(){
        init();
        printf("%lld\n",cald(min(n,m),n,m));
    }
}t;
int main(){
    get(1e7+2);
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;++i)
        t.run();
    return 0;
}

4.P2568:

很不理解,我预处理1e7会挂,但预处理n就不挂了,难道又是数据水?根本没有1e7的数据?

#include<bits/stdc++.h>
using namespace std;
const int M=1e7+20;
#define LL long long
int cnt,mu[M],prime[M],vis[M];
int f[M];
void get(int n){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i])
            prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=cnt;++i)
        for(int j=1;j*prime[i]<=n;++j)
            f[j*prime[i]]+=mu[j];
    for(int i=1;i<=n;++i)
        f[i]+=f[i-1];
}
struct Task{
    int n;
    void init(){
        scanf("%d",&n);
    }
    LL cald(int k,int n,int m){
        LL ans=0;
        for(int l=1,r;l<=k;l=r+1)
            r=min(n/l?min(k,n/(n/l)):k,m/l?min(k,m/(m/l)):k),ans+=1LL*(f[r]-f[l-1])*(n/l)*(m/l);
        return ans;
    }
    void run(){
        init();
        get(n);
        printf("%lld\n",cald(n,n,n));
    }
}t;
int main(){
    t.run();
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!