目录
B - Sum of Consecutive Prime Numbers
E - Exam in BerSU (hard version)
A - 敌兵布阵
题意:
中文你我?懂?
思路:
单点修改,区间查询 => 入门线段树√
-
考察点:线段树,数据结构
代码:
//cin卡时间,关闭输入流
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+100;
struct node
{
int l,r;
int sum;
}tree[maxn*4];
int a[maxn];
inline void build(int i,int l,int r){ ///O(n)
tree[i].l=l;
tree[i].r=r;
if(l==r){
tree[i].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}
inline void update(int i,int l,int r,int x){ ///O(nlogn) O(logn)
if(tree[i].l==l&&tree[i].r==r){
tree[i].sum+=x;
return;
}
if(tree[i*2].r>=l) update(i*2,l,r,x);
if(tree[i*2+1].l<=r) update(i*2+1,l,r,x);
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}
inline int query(int i,int l,int r){ ///O(logn)
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].sum;
if(tree[i].l>r||tree[i].r<l)
return 0;
int s=0;
if(tree[i*2].r>=l) s+=query(i*2,l,r);
if(tree[i*2+1].l<=r) s+=query(i*2+1,l,r);
return s;
}
int main(){
int t,cnt=0,x,y;
ios::sync_with_stdio(false);
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
cout<<"Case "<<++cnt<<":"<<endl;
string ss;
while(cin>>ss){
if(ss=="End")
break;
else{
cin>>x>>y;
if(ss=="Query")
{
cout<<query(1,x,y)<<endl;
}
else if(ss=="Add")
update(1,x,x,y);
else
update(1,x,x,-y);
}
}
}
}
B - Sum of Consecutive Prime Numbers
题意:
一些正整数可以由连续的素数相加而成。
给定数字n,求出有多少种方案。
思路:
第一步:欧拉筛筛出10000之内的所有素数。
第二步:暴力枚举结果 / 进行尺取
-
考察点:枚举,素数,思维,尺取
代码:
#include<iostream>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e4+500;
int prime[maxn]; ///prime[0]
bool is_prime[maxn];
void init(){ ///欧拉筛
memset(is_prime,false,sizeof(is_prime));
is_prime[0]=is_prime[1]=true;
prime[0]=0;
for(int i=2;i<=10000;i++){
if(!is_prime[i])
prime[++prime[0]]=i;
for(int j=1;j<=prime[0];j++){
if(i*prime[j]>10000) break;
is_prime[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
int main()
{
init();
int n;
while(cin>>n&&n){
int cnt=0;
for(int i=1;i<=prime[0];i++){
int sum=0;
for(int j=i;j<=prime[0];j++){
sum+=prime[j];
if(sum>=n) break;
}
if(sum==n)
cnt++;
}
cout<<cnt<<endl;
}
}
C - 天上的星星
题意:
我麻了,但你们懂的8.
思路:
二维前缀和,求(0,0)~(i,j)的星星亮度和存储起来。
//a[i][j]:(i,j)处的星星亮度 sum[i][j]:(0,0)~(i,j)围成的矩形区域的总亮度
if(i>0) sum[i][j]+=sum[i-1][j];
if(j>0) sum[i][j]+=sum[i][j-1];
if(i>0&&j>0) sum[i][j]-=sum[i-1][j-1];
sum[i][j]+=a[i][j];
如何求(x,y)~(c,z)围成的矩形的亮度:
int ans=sum[c][z];
if(x) ans-=sum[x-1][z];
if(y) ans-=sum[c][y-1];
if(x&&y) ans+=sum[x-1][y-1]; //多减去一块补上
-
考察点:二维前缀和,数学,思维
代码:
#include<bits/stdc++.h>
using namespace std;
int a[2050][2050]={0};
int sum[2050][2050]={0}; //sum[i][j]:sum[0][0]与sum[i][j]围成的矩形区域的亮度
int main()
{
int n,x,y,w,q,c,z;
ios::sync_with_stdio(false);
cin>>n;
for(int i=0; i<n; i++)
{
cin>>x>>y>>w;
a[x][y]+=w;
}
for(int i=0; i<=2000; i++)
for(int j=0; j<=2000; j++)
{
if(i>0)
sum[i][j]+=sum[i-1][j];
if(j>0)
sum[i][j]+=sum[i][j-1];
if(i>0&&j>0)
sum[i][j]-=sum[i-1][j-1];
sum[i][j]+=a[i][j];
}
// for(int i=0; i<=10; i++)
// {
// for(int j=0; j<=10; j++)
// cout<<sum[i][j]<<" ";
// cout<<endl;
// }
cin>>q;
for(int i=1; i<=q; i++)
{
cin>>x>>y>>c>>z;
int ans=sum[c][z];
//cout<<ans<<endl;
if(x)
ans-=sum[x-1][z];
if(y)
ans-=sum[c][y-1];
if(x&&y)
ans+=sum[x-1][y-1];
cout<<ans<<endl;
}
}
D - Graveyard Design
题意:
给定一个数n,问有多少种方案满足:
连续的数的平方和等于n。
举例:2030=21^2+22^2+23^2+24^2。
输出区间元素个数与区间内的元素。
思路:
裸的尺取,尺取上限:sqrt(n)。中间记得记录答案,注意输出。
-
考察点:尺取,思维,数学
代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
struct node
{
int l,r;
}a[maxn];
int main()
{
ll n;
while(cin>>n){
ll len=sqrt(n);
ll l=1,r=1;
ll sum=0;
int cnt=0;
while(l<=len){
while(sum<n&&r<=len){
sum+=r*r;
r++;
}
if(sum<n) break;
if(sum==n){
a[++cnt].l=l;
a[cnt].r=r;
//cout<<a[cnt].l<<" "<<a[cnt].r<<endl;
}
sum-=l*l;
l++;
}
cout<<cnt<<endl;
for(int i=1;i<=cnt;i++){
cout<<a[i].r-a[i].l<<" ";
for(int j=a[i].l;j<a[i].r-1;j++)
cout<<j<<" ";
cout<<a[i].r-1<<endl;
}
}
}
E - Exam in BerSU (hard version)
题意:
现在有一场考试,全场时长M分钟,一共有n个同学。
只有当第i名同学解完题目或者放弃做题的时候,第i+1名同学才能开始做题。每名同学需要ai的时间做题。
对于第i名同学来说,在他之前至少有多少人放弃考试他才能在规定时间内完成考试呢?
思路:
这个题其实十分简单,对当前已经考完试的同学贪心就好了。
首先统计时间,对于下一个同学,假设当前的时间为sum,这位同学的考试时间为T,存在以下两种情况:
- sum+T<=m 没有人会痛苦
- sum+T>m 找到之前考试时间最长的那几个gdx,然后_________。
剩下的看代码吧。
-
考察点:贪心,枚举,思维
代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define inf 0x3f3f3f3f
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1e4+500;
int num[105]; ///num[i]:考试时间为i的同学人数
int main()
{
int n,m;
cin>>n>>m;
ll sum=0,t;
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
{
cin>>t;
sum+=t;
if(sum<=m)
cout<<"0 ";
else{
ll sum2=sum;
ll cnt=0;
for(int j=100;j>0;j--){ ///贪心策略
if(num[j]==0) continue;
sum2-=num[j]*j;
cnt+=num[j];
if(sum2<=m){
cnt-=(m-sum2)/j; ///不能全部踢掉,踢掉最有必要的
break;
}
}
cout<<cnt<<" ";
}
num[t]++;
}
cout<<endl;
}
F - Maximum Sum
题意:
求一个矩阵的子矩阵,使得这个子矩阵的和最大。输出这个和。
思路:
暴力枚举出所有可能。
-
考察点:暴力,枚举,矩阵求和,最大子序列求和
代码:
///111
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int a[150][150];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
int ans=0;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++){ ///i j形成竖着的两面墙
int sum=0;
for(int k=1;k<=n;k++) ///k遍历行
{
for(int c=i;c<=j;c++)
sum+=a[k][c];
if(sum<0) sum=0;
ans=max(sum,ans);
}
}
cout<<ans<<endl;
return 0;
}
G - Pie
题意:
你在过生日,你有m个朋友,你有n个馅饼,每个馅饼都是圆柱体,高相同但半径不同
第i个馅饼的半径为ai
要保证每个人得到的馅饼体积相等。
问:每个人最后可以拿到的馅饼最大是多少?
思路:
二分答案模板题。
-
考察点:二分,思维
-
坑点:精度要求较高
代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define inf 0x3f3f3f3f
#define PI acos(-1.0)
using namespace std;
const int maxn=1e4+500;
double a[maxn];
int n,m;
bool check(double x){
int ans=0;
for(int i=1;i<=n;i++){
ans+=(int)(a[i]/x);
if(ans>=m)
return true;
}
return false;
}
int main()
{
int t,x;
scanf("%d",&t);
while(t--){
double l=0,r=0;
scanf("%d%d",&n,&m);
m++; ///还要算上自己的
for(int i=1;i<=n;i++){
scanf("%d",&x);
a[i]=PI*x*x*1.0;
r+=a[i];
}
r/=m;
while((r-l)>1e-6){
double mid=(l+r)/2;
if(check(mid)){
l=mid;
}
else
r=mid;
}
printf("%.4lf\n",l);
}
}