2018年湘潭大学程序设计竞赛题解

时间统计

模拟题

#include <bits/stdc++.h>
using namespace std;
string str;

int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int t[2];
        for(int c=0; c<2; c++)
        {
            cin>>str;
            int len=str.size();
            int k=0;
            while(str[k]!='d')
                k++;
            int x=0;
            for(int i=0; i<k; i++)
            {
                x=x*10+str[i]-'0';
            }
            k+=3;
            int h=0,m=0,s=0;
            int i=k;
            //for(int i=k;i<len;i++)
            {
                h=(str[i]-'0')*10+str[i+1]-'0';
                m=(str[i+3]-'0')*10+str[i+4]-'0';
                s=(str[i+6]-'0')*10+str[i+7]-'0';
            }
            int ans=((24*x+h)*60+m)*60+s;
            //cout<<ans<<endl;
            t[c]=ans;
        }
        cout<<t[1]-t[0]<<endl;

    }
    return 0;
}

String

用数组h存行的编号,用数组l存列的编号。
通过一个三重循环将正方形中的字符与字符串S进行比较,维护数组x和y。x[i]表示第i行的字符出现的次数,y[j]表示第j列的字符出现的次数。
然后遍历x和y找出最大行和最大列并将编号存入相应的数组中。

#include <bits/stdc++.h>
using namespace std;
char a[6][6]={'0','1','2','3','4','5',
'6','7','8','9','A','B',
'C','D','E','F','G','H',
'I','J','K','L','M','N',
'O','P','Q','R','S','T',
'U','V','W','X','Y','Z'};
int x[6],y[6];
vector<int> h,l;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        string s;
        cin>>s;
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        h.clear();
        l.clear();
        int len=s.size();
        for(int i=0;i<6;i++)
            for(int j=0;j<6;j++)
        {
            char c=a[i][j];
            int sum=0;
            for(int k=0;k<len;k++)
            {
                if(c==s[k]) sum++;
            }
            x[i]+=sum;
            y[j]+=sum;
        }
        int max_x=0,max_y=0;
        for(int i=0;i<6;i++)
        {
            max_x=max(max_x,x[i]);
            max_y=max(max_y,y[i]);
        }
        for(int i=0;i<6;i++)
        {
            if(x[i]==max_x) h.push_back(i);
            if(y[i]==max_y) l.push_back(i);
        }
        for(int i=0;i<h.size();i++)
            for(int j=0;j<l.size();j++)
        {
            cout<<a[h[i]][l[j]];
        }
        cout<<endl;
    }
    return 0;
}

Boom

注意到x和y都是整数,把区域分成一个一个的格子,设a[i][j]表示第i行第j列的格子被几个炸弹波及。对于每一个矩形区域,通过一个二重循环维护数组a。然后a中的最大值即为所求。

#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
int a[maxn][maxn];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        memset(a,0,sizeof(a));
        int n;
        cin>>n;
        while(n--)
        {
            int x1,y1,x2,y2;
            cin>>x1>>y1>>x2>>y2;
            for(int i=x1;i<x2;i++)
                for(int j=y1;j<y2;j++)
                a[i][j]++;
        }
        int ans=0;
        for(int i=0;i<maxn;i++)
            for(int j=0;j<maxn;j++)
            ans=max(ans,a[i][j]);
        cout<<ans<<endl;
    }
    return 0;
}

Fibonacci进制

模拟题
题干说可以转化为多个值,取最小的值。但可以观察规律只转化成最小的值。
从最低位向高位依此填数,当填到第i位不够时,从前i-1位选若干位,将其值置为0来弥补空缺。而从前i-1位选时,优先选最接近的值。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

const int maxn=45;

map<int,int> m;
int a[maxn],cnt,f[maxn];
long long ans,p[65];

void solve(int x)
{
    memset(a,0,sizeof(a));
    int i=0;
    while(true)
    {
        if(x==0) break;
        if(x>=f[i])
        {
            x-=f[i];
            a[i]=1;
            i++;
        }
        else
        {
            a[i]=1;
            x=f[i]-x;
            while(x)
            {
                int pos=lower_bound(f,f+cnt,x)-f;
                if(f[pos]!=x) pos--;
                a[pos]=0;
                x-=f[pos];
            }
        }
    }
    ans=0;
    for(int j=0;j<=i;j++)
    {
        if(a[j]) ans+=p[j];
    }
    cout<<ans<<endl;
}
void init()
{
    cnt=0;
    f[0]=1;f[1]=2;
    for(int i=2;i<maxn;i++)
    {
        f[i]=f[i-1]+f[i-2];
        m[f[i]]=i;
        cnt++;
        if(f[i]>INF) break;
    }
    p[0]=1;
    for(int i=1;i<65;i++)
        p[i]=p[i-1]*2;
}
int main()
{
    int T;
    cin>>T;
    init();
    while(T--)
    {
        int x;
        cin>>x;
        solve(x);
    }
    return 0;
}

吃货

用结构体来存放美食的价格和美味度。
对结构体数组按照价格低优先、同等价格美味度低优先排序。然后二分求出t元能买的美食的区间上界pos,答案就是[0,pos]的最大美味度。每次都进行循环来查询太慢了,可以设dp[i]表示区间[0,i]的最大美味度,这样,预处理dp后就可以做到O(1)查询。

#include <bits/stdc++.h>
using namespace std;

const int maxn=3e4+100;
struct node
{
    int d,c;
    bool operator<(const node &o)const
    {
        return d<o.d || d==o.d&&c<o.c;
    }
}a[maxn];
int b[maxn],dp[maxn];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%d%d",&a[i].d,&a[i].c);
        sort(a,a+n);
        memset(dp,0,sizeof(dp));
        dp[0]=a[0].c;
        for(int i=0;i<n;i++)
        {
            b[i]=a[i].d;
            if(i==0) continue;
            dp[i]=max(dp[i-1],a[i].c);
        }

        while(m--)
        {
            int x;
            scanf("%d",&x);
            int pos=upper_bound(b,b+n,x)-b;
            if(b[pos]!=x) pos--;
            printf("%d\n",pos<0?0:dp[pos]);
        }

    }
    return 0;
}

又见斐波那契

矩阵快速幂。
根据递推公式:F(i)=F(i-1)+F(i-2)+i^3+i^2+i+1,
我们可以确定答案矩阵为F(i)+F(i-1)+(i+1)^3+(i+1)^2+(i+1)+1.
根据这两个矩阵,可以确定矩阵A和幂的次数为n-1.

#include <bits/stdc++.h>
#define mod 1000000007
using namespace std;

struct matrix
{
    long long m[6][6];
    matrix()
    {
        memset(m,0,sizeof(m));
    }
};

matrix mul_mod(matrix a,matrix b)
{
    matrix c;
    for(int i=0; i<6; i++)
        for(int j=0; j<6; j++)
            for(int k=0; k<6; k++)
                c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j]%mod)%mod;
    return c;
}
matrix pow_mod(matrix a,long long n)
{
    matrix ans=a,x=a;
    n--;
    while(n>0)
    {
        if(n&1)
            ans=mul_mod(ans,x);
        n>>=1;
        x=mul_mod(x,x);
    }
    return ans;
}
void solve(long long n)
{
    matrix tmp,ans,A;
    A.m[0][0]=1;
    A.m[0][1]=1;
    A.m[1][0]=1;
    A.m[2][0]=1;
    A.m[2][2]=1;
    A.m[3][0]=1;
    A.m[3][2]=3;
    A.m[3][3]=1;
    A.m[4][0]=1;
    A.m[4][2]=3;
    A.m[4][3]=2;
    A.m[4][4]=1;
    A.m[5][0]=1;
    A.m[5][2]=1;
    A.m[5][3]=1;
    A.m[5][4]=1;
    A.m[5][5]=1;

    tmp.m[0][0]=1;
    tmp.m[0][1]=0;
    tmp.m[0][2]=8;
    tmp.m[0][3]=4;
    tmp.m[0][4]=2;
    tmp.m[0][5]=1;
    if(n==1)
        printf("%lld\n",1);
    else
    {
        A=pow_mod(A,n-1);
        ans=mul_mod(tmp,A);
        printf("%lld\n",ans.m[0][0]);
    }

}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long n;
        scanf("%lld",&n);
        solve(n);
    }
    return 0;
}

统计颜色

定义一个二元组数组col,col[i]表示颜色为i的球,col[i]里面存放的是颜色为i的球在桶中的区间范围。每次查询区间[l,r]的桶中不同颜色的球时,枚举所有颜色的球,当col[i]中的区间与[l,r]有重叠时,计数加一。因为球的颜色数不超过61,所有时间不会超限。

#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pa;
vector<pa> col[62];

void solve(int l,int r)
{
    int ans=0;
    for(int i=0;i<=60;i++)
    {
        for(int j=0;j<col[i].size();j++)
        {
            int x=col[i][j].first,y=col[i][j].second;
            if(x<=l&&r<=y || l<x&&r>=x || l<=y&&r>y)
            {
                ans++;
                break;
            }
        }
    }
    printf("%d\n",ans);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0;i<62;i++) col[i].clear();
        int op,l,r,c;
        while(m--)
        {
            scanf("%d%d%d",&op,&l,&r);
            if(op==1)
            {
                scanf("%d",&c);
                col[c].push_back(pa(l,r));
            }
            else
            {
                solve(l,r);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值