7.16SMU Summer 2024 Contest Round 4

E题--Red and Green Apples

http://162.14.124.219/contest/1008/problem/E

先分别将输入的三个数组进行排序,然后分别将红苹果中前X大的数和绿苹果中前y个数进行相加,并将它们存入一个vector中,对这个vector进行排序,将这个vector中最小的数据与白苹果中最大的数据进行比较,如果大于就进行替换,以此类推。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e15 + 7;
int x,y,a,b,c;
int nn[100005],mm[100005],ss[100005];
int sum;
int ans;
vector<int> ve;
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>x>>y>>a>>b>>c;
    for(int i=1;i<=a;i++){
        cin>>nn[i];
    }
    sort(nn+1,nn+1+a);
    //for(int i=1;i<=a;i++) cout<<nn[i]<<' ';
    for(int i=1;i<=b;i++){
        cin>>mm[i];
    }
    sort(mm+1,mm+1+b);
    for(int i=1;i<=c;i++){
        cin>>ss[i];
    }
    sort(ss+1,ss+1+c);
    //for(int i=1;i<=c;i++) cout<<ss[i]<<' ';
    //cout<<endl;
    for(int i=a;i>a-x;i--){
        sum+=nn[i];
        ve.push_back(nn[i]);
    }
   // cout<<"sum="<<sum<<endl;
    for(int i=b;i>b-y;i--){
        sum+=mm[i];
        ve.push_back(mm[i]);
    }
    //cout<<"sum="<<sum<<endl;
    ans=x+y;
    sort(ve.begin(),ve.end());
    /*for(int i=0;i<ans;i++){
        cout<<ve[i]<<' ';
    }
    cout<<endl;*/
    int j=0;
    for(int i=c;i>=1;i--){
        if(ss[i]>ve[j]){
            sum-=ve[j];
            sum+=ss[i];
            j++;
        }
        else if(ss[i]<=ve[j]) break;
        else if(j>=ans) break;
    }
    cout<<sum<<endl;
}

B题--H and V

http://162.14.124.219/contest/1008/problem/B
考试的时候根本没有想到二进制枚举,反而在哪一直写循环,再到后来给自己绕晕了彻底写不出来。

实际上在存储该数组的时候就可以使用二进制,对于#存为1,其余为零。而后分别枚举行和列的情况(行有2<<n种情况,列有2<<m种情况)。再去进行一个计数,如果数组中的#所对应的行和列都别选择时,cnt++。在循环完一次后,如果cnt==k,那么sum+1.

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e15 + 7;
int sum;
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int n,m,k;
    int a[8][8];
    cin>>n>>m>>k;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            char ch;
            cin>>ch;
            a[i][j]=(ch=='#');
        }
    }
    int sum=0;
    for(int i=0;i<(1<<n);i++){
        for(int j=0;j<(1<<m);j++){
            int cnt=0;
            for(int x=0;x<n;x++){
                for(int y=0;y<m;y++){
                    if(a[x][y]&&(i&1<<x)&&(j&1<<y)) cnt++;
                }
            }
            if(cnt==k) sum++;
        }
    }
    cout<<sum<<endl;
}

D题--Sum of Divisors

http://162.14.124.219/contest/1008/problem/D

开始的时候想的是直接去求,对于每一个小于n的数i进行开放并取整位为k,循环每一个小于k的数,然后i对k求余,如果余数是0,则f(i)+2;如果k*k=i时,f(i)-1;这样计算出的答案是对的,但是时间上会超时。

错误代码:
 

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e15 + 7;
int temp(int x){
    int ans=0;
    int k=sqrt(x);
    
    for(int i=1;i<=k;i++){
        if(x%i==0) ans+=2;
    }
    if(k*k==x) ans-=1;
    return ans;
}
int sum;
int k;
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int n;
    cin>>n;
    int a[10000005];
    for(int i=1;i<=n;i++){
        sum+=i*temp(i);
        //cout<<i<<' '<<temp(i)<<endl;
        //cout<<"sum="<<sum<<
    }
    cout<<sum<<endl;
}

然后就想办法优化,受到求素数的启发,想出来实际上每个数有多少个正因子,不如看成每一个数i(1<=i<=10000000)乘上j(1<=j&&i*j<=10000000)倍后的数是否在10000000范围内,如果在,a[i*j]++;为了防止超时,在初始化数组的时候直接让奇数i的a[1]=1,偶数i的a[i]=2(实际上就是每一个数都有一个正因子1,每一个偶数都有一个正因子2)。i将从三开始循环。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e15 + 7;
int a[10000005];
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=10000000;i++){
        if(i%2==0) a[i]=2;
        else a[i]=1;
    }
    for(int i=3;i<=10000000;i++){
        for(int j=1;j*i<=10000000;j++){
            int k=i*j;
            a[k]++;
        }
    }
    int sum=0;
    for(int i=1;i<=n;i++){
        sum+=i*a[i];
        //cout<<i<<' '<<a[i]<<endl;
    }
    cout<<sum<<endl;
}

F题--Rem of Sum is Num

http://162.14.124.219/contest/1008/problem/F

由于求的是子序列,所以想到用前缀和来求。a[i]为原数组,sum[i]为前缀和。所以由题意得,连续子序列对k求余后的余数等于子序列中元素个数。就相当于(sum[j]-sum[i])%k=j-i;令(sum[j]-sum[i])/k=x(x为任意实数,无需计较)。所以sum[j]-sum[i]=k*x+j-i,变形可得(sum[j]-j)-(sum[i]-i)=k*x;所以可知(sum[j]-j)%k-(sum[i]-i)%k=0。最后开一个map用来确定min(k-1,n)中满足要求的数。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e15 + 7;
int n,k;
int sum[200005];
int ans;
map<int,int> mp;
signed main(){
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>k;
    sum[0]=0;
    for(int i=1;i<=n;i++){
        int m;
        cin>>m;
        sum[i]=sum[i-1]+m;
    }
    /*for(int i=0;i<=n;i++){
        cout<<sum[i]<<' ';
    }
    cout<<endl;*/
    for(int i=1;i<=n;i++){
        sum[i]-=i;
        sum[i]%=k;
    }
    int mm=min(k-1,n);
    for(int i=0;i<=mm;i++){
        ans+=mp[sum[i]];
        mp[sum[i]]++;
    }
    for(int i=mm+1;i<=n;i++){
        mp[sum[i-k]]--;
        ans+=mp[sum[i]];
        mp[sum[i]]++;
    }
    cout<<ans<<endl;
}

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值