COCI 2013/2014 1st round, September 28th, 2013 解题报告

本文解析了五道编程挑战题目,包括统计特定首字母的名字、计算香肠分配所需的切割次数、寻找权值和相等的长方形组合、最大化背包装载价值及确定进入决赛的最大人数。通过实际代码示例展示了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TRENER

给出一堆人的英文名字(全是小写字母),若有一些字母作为首字母出现不少于5次,则输出所有符合条件的字母。

每读入一个姓名,就给该姓名首字母的次数+1。最后扫一遍所有字母作为首字母出现的次数,大于等于5的输出。

#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
int n,a[28];
bool flag;
int main(){
    freopen("trener.in","r",stdin);
    freopen("trener.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++){
        string tmp;
        cin>>tmp;
        a[tmp[0]-'a']++;
    }
    for(int i=0;i<26;i++){
        if(a[i]>=5){
            char out=i+'a';
            cout<<out;
            flag=1;
        }
    }
    if(!flag)
        cout<<"PREDAJA";
    cout<<endl;
    return 0;
}

KUŠAČ

给出一些完全相等的香肠和参会人数,香肠需要平分给所有人,至少要切几刀可以使每个人得到等量的香肠?

模拟题,将所有香肠首尾相连成一条长香肠,给每个人按顺序切一段,若切的地方刚好是连接处,则不必计数,否则答案+1。输出答案即可。

#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
int n,m,ans;
int main(){
    freopen("kusac.in","r",stdin);
    freopen("kusac.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=0;i<=n*m;i+=n) if(i%m) ans++;
    cout<<ans<<endl;
    return 0;
}

RATAR

给出一个正方形中每个小方格的权值,问有多少种长方形组合,使该两个长方形权值和相等且两个长方形顶角相连。

f[i][j]表示以(i,j)为右下角的长方形的权值和。首先用求前缀和的方式求出所有的f[i][j],这样就能快速算出各个矩形的权值和。然后n^2枚举每一个点,并n^2枚举所有以该点为右下角的矩形,计算各个权值的数量。接下来n^2枚举所有以(i+1,j+1)为右上角的矩形,加上刚才算的该权值的矩形的数量。同理处理(i,j)分别为两个矩形的右下角和左上角的情况。
注意,每次枚举完一个点都要重新计数。

#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int c=2500000;
int n,f[55][55],tot,ans;
int cnt[2*c];
int cal(int x1,int y1,int x2,int y2){
    return f[x2][y2]-f[x1-1][y2]-f[x2][y1-1]+f[x1-1][y1-1];
}
int main(){
    freopen("ratar.in","r",stdin);
    freopen("ratar.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>f[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]+=f[i][j-1];
    for(int j=1;j<=n;j++)
        for(int i=1;i<=n;i++)
            f[i][j]+=f[i-1][j];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int a=1;a<i;a++)
                for(int b=1;b<j;b++)
                    cnt[cal(a,b,i-1,j-1)+c]++;
            for(int a=i;a<=n;a++)
                for(int b=j;b<=n;b++)
                    ans+=cnt[cal(i,j,a,b)+c];
            for(int a=1;a<i;a++)
                for(int b=1;b<j;b++)
                    cnt[cal(a,b,i-1,j-1)+c]--;
            for(int a=i;a<=n;a++)
                for(int b=1;b<j;b++)
                    cnt[cal(i,b,a,j-1)+c]++;
            for(int a=1;a<i;a++)
                for(int b=j;b<=n;b++)
                    ans+=cnt[cal(a,j,i-1,b)+c];
            for(int a=i;a<=n;a++)
                for(int b=1;b<j;b++)
                    cnt[cal(i,b,a,j-1)+c]--;
        }
    }
    cout<<ans<<endl;
    return 0;
}

LOPOV

给出一些物品的重量和权值,给出一些背包的容量,且每个背包最多放一件物品,求能装下的物品的权值和最大是多少。

将每个背包当做权值为-1的物品, 与其他物品一起,按照重量由小到大排序,若重量相等,则按权值由大到小排序(确保同重量的时候背包在物品后)。建立一个优先队列,遍历所有物品和背包,若权值不为-1,即该物品不为背包,则将该物品的权值加入优先队列;若权值为-1,该物品为背包,则将优先队列队首的元素取出加入答案。(这个方法跑的比标程快233)

#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=600005;
int n,k;
ll ans;
struct no{
    int m,v;
}a[M];
priority_queue<int> q;
bool cmp(no a,no b){
    return a.m!=b.m?a.m<b.m:a.v>b.v;
}
int main(){
    freopen("lopov.in","r",stdin);
    freopen("lopov.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i].m>>a[i].v;
    for(int i=1;i<=k;i++){
        cin>>a[i+n].m;
        a[i+n].v=-1;
    }
    sort(a+1,a+n+k+1,cmp);
    for(int i=1;i<=n+k;i++){
        if(a[i].v!=-1)
            q.push(a[i].v);
        else if(!q.empty()){
            ans+=q.top();
            q.pop();
        }
    }
    cout<<ans<<endl;
    return 0;
}

ORGANIZATOR

给出若干个俱乐部的人数,由你制定每个比赛队伍的人数,每个队伍的人必须来自同一个俱乐部,若某个俱乐部的成员不能全员参加比赛,该俱乐部便不会参加比赛。每个俱乐部的排名第一的队伍将进入比赛(若进入决赛的队伍少于2支便不算决赛)。求问最多能有多少人数进入决赛。

转化一下,其实这道题便是给出一堆数字,求找一个数,使能整除该数的数的个数(必须不小于2)*该数的值最大,输出这个最大值。
对输入的每个数进行计数,然后开始从1到2000000枚举数i,将所有是i的倍数的数的数量加和,若数量和*i大于当前答案则更新答案。

#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=2000005;
int n,a[M];
ll ans;
int main(){
    freopen("organizator.in","r",stdin);
    freopen("organizator.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        a[x]++;
    }
    for(int i=1;i<=2000000;i++){
        int cur=0;
        for(int j=i;j<=2000000;j+=i)
            cur+=a[j];
        if(cur>1) ans=max(ans,(ll)cur*i);
    }
    cout<<ans<<endl;
    return 0;
}

SLASTIČAR

给出一个A串,和一些B串,开始进行匹配,匹配方法是对于逐位对比,若有某一位不同则从起始位置的下一位开始重新匹配(也就是暴力匹配),若匹配成功或匹配到A串尾依然无法匹配成功,则停止匹配。每匹配一位消耗1单位时间,分别求出匹配每个串的时间。

正在研究中,稍后奉上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值