第二题难度每年不一,简单的年份理解清题意、想好每一步干什么、用什么数据结构存储,然后直接翻译就可以了,如果要加难度,基本都是时间复杂度方面,常见的方法有动态规划/差分/前缀和等等
目录
2021-09-2 非零段划分
2021-06-2 领域均值
2020-09-2 风险人群筛查
2020-06-2 稀疏向量
2019-12-02 回收站选址
2019-09-2 小明种苹果(续)
法一:暴力法 for(p=0;p<=maxp;p++) 对每个p求对应的非零段数量,记录最大值 70分
法二:差分法:以变化的视角来看待,观察p每次-1(或+1)时,非零段个数的变化,可以发现影响非零段数量的本质是“凸”和“凹”的情况
思想:将数组中每个值看成对应高度的“山峰”,题中的p相当于“海平面”,所求就是高于海平面的“岛屿”(由若干连续的山峰组成)个数
分两种情况:
两高夹一矮 则当海平面下降到矮峰下面时,就会连起来,岛屿数-1
两矮夹一高 则当海平面下降到高峰下面时,岛屿数+1
将凸和凹的组数保存到ans[]数组中,ans的索引代码山峰的高度,最后在ans数组叠加的过程中记录最大值即可
#include
using namespace std;
int a[500005];
int cnt[10005];
int main(){
int n;
cin>>n;
a[0]=0;for(int i=1;i<=n;i++)cin>>a[i];a[n+1]=0;
n=unique(a,a+n+2)-a;
for(int i=1;ia[i+1])
cnt[a[i]]++;
else if(a[i-1]>a[i]&&a[i]0;i--){
sum+=cnt[i];
ans=max(ans,sum);
}
cout<
二维前缀和
参考了这篇大佬的博客 (206条消息) CSP-2邻域均值_Vanghua的博客-CSDN博客,不过自己习惯用x表示行(i),用y表示列(j),本质其实一样的。
第一个循环中i,j的含义是矩阵的右下角
第二个循环中i,j是矩阵的中心,(xl,yt)是矩阵左上角,(xr,yb)是矩阵右下角
#include
using namespace std;
int ar[601][601], sum[601][601];
int main() {
int n, l, r;
float t;
cin >> n >> l >> r >> t;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++) {
cin >> ar[i][j];
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + ar[i][j];
}
int xl, xr, yt, yb, sumVal, cnt = 0;
float avgVal;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++) {
yt = j - r >= 1 ? j - r : 1;
yb = j + r <= n ? j + r : n;
xl = i - r >= 1 ? i - r : 1;
xr = i + r <= n ? i + r : n;
sumVal = sum[xr][yb] - sum[xl - 1][yb] - sum[xr][yt-1] + sum[xl - 1][yt - 1];
avgVal = (float)sumVal / ((yb - yt + 1) * (xr - xl + 1));
if(avgVal <= t)
cnt ++;
}
cout << cnt;
}
没用什么算法
理解清题意,直译,f1记录是否经过,f2记录是否停留,pass表示经过人数,stay表示停留人数,内循环结束后根据f1,f2进行pass++,stay++
#include
using namespace std;
const int maxn=10005;
int x[maxn],y[maxn];
int main(){
int n,k,t,xl,yd,xr,yu;
cin>>n>>k>>t>>xl>>yd>>xr>>yu;
int stay=0,pass=0;
for(int j=0;j>x[i]>>y[i];
if(xl<=x[i]&&xr>=x[i]&&yd<=y[i]&&yu>=y[i])
{
cnt++;
f1=1;
if(cnt>=k)f2=1;
}
else cnt=0;
}
if(f1)pass++;
if(f2)stay++;
}
cout<
遍历其中一个向量的非零项索引,查找另一个向量中对应的地方是否也为非零项(相当于查看x[N]或y[N]中是否也有该索引),若有则相乘并累加
其中优化时间复杂度的地方在于,观察可以发现题目中给出的索引都是从小到大排列的,因此在查找的过程当中,不需要找到尾部,一旦大于索引就可以终止查找,并且不需要每次从头查找,只要在每次查找完用一个全局变量标记当前位置,下次接着往后找就行,因此时间复杂度是线性的
#include
using namespace std;
int n,a,b;
const int N=5e5+5;
int x[N],y[N];
long u[N],v[N];
long long ans=0;
int w=0;
int search(int f,int c){
for(int k=w;kf){
w=k;
return -1;
}
}
return -1;
}
int main(){
cin>>n>>a>>b;
for(int i=0;i>x[i]>>u[i];
for(int j=0;j>y[j]>>v[j];
if(a<=b){
for(int i=0;i
没用什么算法
直译,先判断能否作为回收站,然后判断能得几分,用f[]记录各个分数的回收站个数
#include
using namespace std;
#define forn(i,n) for(int i=0;i>n;forn(i,n){cin>>p[i].x>>p[i].y;}
forn(i,n){
if(find(p[i].x-1,p[i].y)&&find(p[i].x,p[i].y+1)
&&find(p[i].x+1,p[i].y)&&find(p[i].x,p[i].y-1)){
int c=0;
if(find(p[i].x-1,p[i].y-1))c++;
if(find(p[i].x-1,p[i].y+1))c++;
if(find(p[i].x+1,p[i].y+1))c++;
if(find(p[i].x+1,p[i].y-1))c++;
f[c]++;
}
}
forn(i,5)cout<
没用什么算法
直译
#include
using namespace std;
#define int long long
int m,n;
int a[1005],b[1005]={0};
bool flag[1005]={0};
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
int total=0,e=0,d=0;
for(int i=0;i>m;
cin>>a[i];
for(int j=1;j>tmp;
if(tmp<=0)a[i]+=tmp;
else
{
if(tmp=1&&i<=n-1&&flag[i]&&flag[i-1]&&flag[i-2])
e++;
}
if(flag[0]&&flag[1]&&flag[n-1])
e++;
if(flag[n-2]&&flag[0]&&flag[n-1])
e++;
cout<