2019爪哇之星程序设计编程赛(个人赛)

文章目录

  • A - 礼尚往来 (错排)
  • C - 屌丝逆袭(模拟)
  • D - 口算训练 (质因数分解)
  • E - 子串查询(前缀和)
  • F - 赛题分析 (模拟)
  • G - CCPC直播 (模拟)
  • H - 电梯爱情故事 (模拟)


A - 礼尚往来 (错排)

原题链接:https://vjudge.net/contest/340569#problem/A


题意: 收到礼物,然后重新放到不同的位置上,问方案有多少个?

思路: 错排模板题,直接套用错排公式并取模即可。

注意要用long long 型,否则WA!

不懂错排公式怎么来的看这里:彻底搞懂错排公式


Code(C++):

#include 
#include 
using namespace std;
typedef long long ll;
ll dp[105];
const int N=1e9+7;
int main(){
    int t;  scanf("%d",&t);
    dp[1]=0;
    dp[2]=1;
    for(int i=3;i<=100;i++)
        dp[i]=(i-1)*(dp[i-1]+dp[i-2])%N;
    while(t--){
        int n;
        scanf("%d",&n);
        printf("%lld\n",dp[n]);
    }
}


C - 屌丝逆袭(模拟)

原题链接:https://vjudge.net/contest/340569#problem/C

题意: 男生魅力值用负整数表示,女生魅力值用正整数表示,如果某位置的邻居和该位置主人性别不同,则总分加上邻居魅力值的绝对值,否则减去。注意这里的魅力总分不包含该位置上的魅力值。

思路: 所有位置的魅力值存入数组 a[ ][ ],数组b[ ][ ]用来存每个位置周围的魅力值总和。然后遍历每个位置,算出该位置周围的魅力值总和,性别相同的,减掉魅力值绝对值,否则加上魅力值绝对值。最后再遍历所有位置,不断更新最大魅力值所在的位置以及总和。


Code(C++):

#include 
#include 
using namespace std;
int a[25][25],b[25][25];
int main(){
    int n,m;
    while(cin>>n>>m){
        if(n==0 && m==0)
            break;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>a[i][j];
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                b[i][j]=0;
                if(a[i][j]>0){
                    if(a[i-1][j]!=0)
                        b[i][j]-=a[i-1][j];
                    if(a[i+1][j]!=0)
                        b[i][j]-=a[i+1][j];
                    if(a[i][j-1]!=0)
                        b[i][j]-=a[i][j-1];
                    if(a[i][j+1]!=0)
                        b[i][j]-=a[i][j+1];
                }
                else if(a[i][j]<0){
                    if(a[i-1][j]!=0)
                        b[i][j]+=a[i-1][j];
                    if(a[i+1][j]!=0)
                        b[i][j]+=a[i+1][j];
                    if(a[i][j-1]!=0)
                        b[i][j]+=a[i][j-1];
                    if(a[i][j+1]!=0)
                        b[i][j]+=a[i][j+1];
                }
            }
        }
        int x=1,y=1,ans=b[1][1];
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(b[i][j]>ans){
                    ans=b[i][j];
                    x=i,y=j;
                }
            }
        }
        cout<<x<<" "<<y<<" "<<ans<<endl;
    }
}


D - 口算训练 (质因数分解)

原题链接:https://vjudge.net/contest/340569#problem/D


题意: 给你n个数a[1]、a[2]… a[n]和m个询问。每一个询问输入l,r,d,询问在区间l和r中,是否满足a[l] * a[l+1] * … * a[r] 能被d整除。

思路: 集训的时候知道直接遍历会TLE,但没什么新的思路,就试了一下Java大整数类暴力遍历,果然,TLE了。对于 k 是不是 d 的倍数,我们可以对这两个数分解质因数,如果满足对于 d 的每一个质因数,在 k 中都有出现过,且在 k 中出现的次数大于等于d的出现次数,则 k 是 d 的倍数。


Code(C++):

#include 
#include 
#include 
#include 
using namespace std;
const int N=1e5+100;
vector<int> v[N];
int main(){
    int t;  scanf("%d",&t);
    while(t--){
        for(int i=1;i<N;i++)    //记得初始化vector
            v[i].clear();
        int n,m;
        scanf("%d%d",&n,&m);
        int x;
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            for(int j=2;j*j<=x;j++){
                while(!(x%j)){
                    v[j].push_back(i);  //该数可分解几次,就存入该数下标几次,注意这里存入的是对应质因数的动态数组
                    x/=j;
                }
            }
            if(x>1) v[x].push_back(i);  //如果该数还没除完,还是个质数,需要再存入一次
        }
        while(m--){
            int l,r,d;
            scanf("%d%d%d",&l,&r,&d);
            int vis=0;
            for(int i=2;i*i<=d;i++){    //分解d的质因数
                int sum1=0;
                while(!(d%i)){
                    sum1++; //记录每个质因数的个数
                    d/=i;
                }
                if(sum1){
                    int sum2=upper_bound(v[i].begin(),v[i].end(),r)-lower_bound(v[i].begin(),v[i].end(),l); //计算每个质因数的总数
                    if(sum2<sum1){  //如果d中的质因数大于k中的,则不符合
                        vis=1;
                        break;
                    }
                }
            }
            if(d>1){    //同理,整除后d还是质数的情况
                int sum2=upper_bound(v[d].begin(),v[d].end(),r)-lower_bound(v[d].begin(),v[d].end(),l);
                if(!sum2)   vis=1;
            }
            if(vis)
                printf("No\n");
            else
                printf("Yes\n");
        }
    }
    return 0;
}


E - 子串查询(前缀和)

原题链接:https://vjudge.net/contest/340569#problem/E


题意: 给定一个字符串,在有限查询次数内输出所要查询区间的字典序最小的子串个数。

思路: 查找给定区间中字典序最小的字母出现的次数。

注意:好像用cin、cout会TLE。


Code(C++):

#include 
#include 
#include 
using namespace std;
const int N=1e5+10;
char s[N];
int a[N][30];   //一维表示下标,二维表示字母
int main(){
    int t;  scanf("%d",&t);
    for(int k=1;k<=t;k++){
        memset(a,0,sizeof(a));  //记得每次输入前初始化
        int n,m;
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);    //下标右移一位
        printf("Case #%d:\n",k);
        for(int i=1;i<=n;i++){
            a[i][s[i]-'A']++;   //记录每个位置字母出现的次数
            for(int j=0;j<26;j++)   //遍历字母表
                a[i+1][j]=a[i][j];  //累加每个字母在前面出现的次数
        }
        while(m--){
            int l,r;
            scanf("%d%d",&l,&r);
            for(int j=0;j<26;j++){
                //如果该区间的前一个区间该字母出现次数与该区间相等,说明该区间没出现该字母
                if(a[l-1][j]!=a[r][j]){ //不相等说明出现,一经出现说明字典序最小,跳出循环
                    printf("%d\n",a[r][j]-a[l-1][j]);
                    break;
                }
            }
        }
    }
    return 0;
}


F - 赛题分析 (模拟)

原题链接: https://vjudge.net/contest/340569#problem/F


题意: 输出验题人中的最小代码字节数和AC队伍中选手最小的代码字节数,若不存在则输出N/A。

思路: 直接模拟即可。


Code(C++):

#include 
#include 
#include 
using namespace std;
int a[100],b[505];
int main(){
    int t;  cin>>t;
    for(int k=1;k<=t;k++){
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        int n,m;
        cin>>n>>m;
        int minn1=70000;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            minn1=min(minn1,a[i]);
        }
        int minn2=70000;
        for(int i=1;i<=m;i++){
            cin>>b[i];
            minn2=min(minn2,b[i]);
        }
        cout<<"Problem "<<1000+k<<":"<<endl;
        cout<<"Shortest judge solution: "<<minn1<<" bytes."<<endl;
        if(m!=0)
            cout<<"Shortest team solution: "<<minn2<<" bytes."<<endl;
        else
            cout<<"Shortest team solution: N/A bytes."<<endl;
    }
}


G - CCPC直播 (模拟)

原题链接: https://vjudge.net/contest/340569#problem/G


题意: 额,直接看原题吧,太长了,中文题目不难理解。

思路: 模拟题,直接看代码吧,不难懂!注意左以及右对齐的写法。


Code(C++):

#include 
#include 
using namespace std;
int main(){
    int t;  cin>>t;
    for(int k=1;k<=t;k++){
        int rank;   cin>>rank;
        string str;
        cin>>str;
        int prob;   cin>>prob;
        string T;
        cin>>T;
        int x;
        if(T=="Running")
            cin>>x;
        cout<<setw(3)<<setfill(' ')<<right<<rank<<"|";
        cout<<setw(16)<<setfill(' ')<<left<<str<<"|"<<prob<<"|";

        if(T=="Running"){
            cout<<"[";
            for(int i=1;i<=x;i++)
                cout<<"X";
            for(int i=1;i<=10-x;i++)
                cout<<" ";
            cout<<"]"<<endl;
        }
        else{
            cout<<"[";
            if(T=="FB"){
                cout<<"    "<<"AC*";
                int len=T.length();
                for(int i=1;i<=5-len;i++)
                    cout<<" ";
                cout<<"]"<<endl;
            }
            else{
                cout<<"    "<<T;
                int len=T.length();
                for(int i=1;i<=6-len;i++)
                    cout<<" ";
                cout<<"]"<<endl;
            }

        }
    }
    return 0;
}


H - 电梯爱情故事 (模拟)

原题链接: https://vjudge.net/contest/340569#problem/H


题意: 电梯每向上运行一层需要6秒钟,向下运行一层需要4秒钟,每开门一次需要5秒(如果有人到达才开门),并且每下一个人需要加1秒。 电梯最开始在0层,并且最后必须再回到0层才算一趟任务结束。求电梯跑一趟所需时间。

思路: 先把所有要去的楼层从小到大排序,对每个数,与前一个数相比,如果相等,说明这两个人都在该层下,则不需要再算开门时间,否则要算上开门时间。


Code(C++):

#include 
#include 
#include 
using namespace std;
int a[105];
int main(){
    int t;  cin>>t;
    while(t--){
        memset(a,0,sizeof(a));
        int n;  cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        sort(a+1,a+1+n);
        int ans=0;
        for(int i=1;i<=n;i++){
            if(a[i]-a[i-1]!=0)
                ans=ans+(a[i]-a[i-1])*6+1+5;
            else
                ans=ans+(a[i]-a[i-1])*6+1;
        }
        ans=ans+a[n]*4;
        cout<<ans<<endl;
    }
    return 0;
}


你可能感兴趣的:(算法)