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;
}