中山Day4——普及

生活开始日益平淡了呢。。。今天130分。

收获:归并排序求逆序对

           背包问题(01、完全、多重)(外带滚动数组优化)


T1:题目链接(才不会告诉你们下面的代码也是洛谷上弄来的)

思路:动态规划。首先,设dp[i][k]为从a1到ak余数等于n的块数。然后先预处理一下,设sum[i][j]为从i到j%m的余数。接着用1至m-1来更新dp。

然后可以推出转移方程为:dp[i][(k*sum[j+1][i])%m]=max(dp[i][(k*sum[j+1][i])%m],dp[j][k]+1)。

这么做的时间复杂度是O(len^2*m),肯定是能过的。

见代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,a[1001],sum[1001][1001],dp[1001][100];
char c[1001];
int main()
{
    
    for(int i=0;i<=1000;i++)
    for(int j=0;j<=50;j++)
    dp[i][j]=0x7f7f7f;
    scanf("%s%d",&c,&m);    
    int len=strlen(c);
    for(int i=0;i<len;i++)
    a[i+1]=c[i]-'0';
    for(int i=1;i<=len;i++)
        for(int j=i;j<=len;j++)
        sum[i][j]=(sum[i][j-1]*10+a[j])%m;
    for(int i=1;i<=len;i++)
    dp[i][sum[1][i]]=1;
    for(int i=1;i<=len;i++)
    {
        for(int j=1;j<i;j++)
        {
            for(int k=0;k<=m-1;k++)
            dp[i][(k*sum[j+1][i])%m]=min(dp[i][(k*sum[j+1][i])%m],dp[j][k]+1);
        }
    }
    for(int i=0;i<=m-1;i++)
    {
        if(dp[len][i]!=0x7f7f7f)
        {
            printf("%d %d ",i,dp[len][i]-1);
            break;
        }
    }
    for(int i=m-1;i>=0;i--)
    {
        if(dp[len][i]!=0x7f7f7f)
        {
            printf("%d %d ",i,dp[len][i]-1);
            break;
        }
    }
    return 0;
}

好题哉!!!


 T2:题目链接(这道我暴力冒泡30分)

思路:其实是很简单的,就是裸的归并排序找逆序对而已,可惜我早上不会,考到也算查漏补缺了。

见代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,a[500001],b[500001];
long long ans;
void merge_sort(int l,int r)
{
    if(r-l>0)
    {
        int mid=(l+r)/2;
        merge_sort(l,mid);
        merge_sort(mid+1,r);
        int i=l,q=mid+1,p=l;
        while(q<=r||p<=mid)
        {
            if(q>r||(p<=mid&&a[p]<=a[q]))
            {
                b[i++]=a[p++];
            }
            else
            {
                b[i++]=a[q++];
                ans+=mid-p+1;
            }
        }
        for(int i=l;i<=r;i++)
        a[i]=b[i];
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    merge_sort(1,n);
    printf("%ld",ans);
    return 0;
}

好题哉!!!


 

T3:题目链接(唯一A掉的一道水题)

思路:第一眼看到k<=1018,就想到了以为叫做小凯的同学。于是就打了个表,发现是个斐波那契数列,然后就递推一下,外加维护一个前缀和,秒做的有没有。

见代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
long long k,i;
struct h{
    long long num1;
    long long num2;
    long long q;
};
h fb[90];
int main()
{
    fb[0].num1=fb[0].num2=1;
    fb[0].q=1;
    scanf("%ld",&k);
    while(fb[i].q<k)
    {
        i++;
        fb[i].num2=fb[i-1].num1;
        fb[i].num1=fb[i-1].num1+fb[i-1].num2;
        fb[i].q=fb[i-1].q+fb[i].num2;
    }
    printf("m=%ld
",fb[i].num2);
    printf("n=%ld",fb[i].num1);
    return 0;
}

好题哉!!!


T4:题目链接

思路,最为清晰的一题:多重背包!!!可惜我又不会。。。恶补了下背包,以后就不会有问题啦,好开心

见代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,c,num,k=0,v[500001],w[500001],dp[500001];
int main()
{
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&v[i],&w[i],&num);
        {
            for(int k=1;k<=num;k++)
            for(int j=c;j>=w[i];j--)
            {
                dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
            }
        }
    }
    printf("%d",dp[c]);
    return 0;
}

可惜这题不开单调队列优化就只有30分。诶……

好题哉!!!

原文地址:https://www.cnblogs.com/qing1/p/11299720.html