P1102 A-B 数对
题目背景
出题是一件痛苦的事情!
相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
题目描述
给出一串正整数数列以及一个正整数 C,要求计算出所有满足 A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个正整数 N,C。
第二行,第 i 个数为 ai,数字之间用一个空格隔开,共 N 个正整数,作为要求处理的那串数。
输出格式
一行,表示该串正整数中包含的满足 A−B=C 的数对的个数。
输入输出样例
输入 #1复制
4 1
1 1 2 3
输出 #1复制
3
说明/提示
对于 75% 的数据,1≤N≤2000。
对于 100% 的数据,1≤N≤2×105,0≤ai<230,1≤C<230。
2017/4/29 新添数据两组
实现代码:
cpp
#include <iostream>
#include <map>
using namespace std;
typedef long long LL;
LL a[200001];
map<LL,LL> m;
int main() {
int n;
LL c;
LL ans=0;
cin >> n >> c;
for(int i=1;i<=n;i++) {
cin >> a[i];
m[a[i]]++;
a[i]-=c;
}
for(int i=1;i<=n;i++) ans+=m[a[i]];
cout << ans << endl;
return 0;
}
P1638 逛画展
题目描述
博览馆正在展出由世上最佳的 m 位画家所画的图画。
游客在购买门票时必须说明两个数字,x 和 y,代表他要看展览中的第 x 幅至第 y 幅画(包含 x,y)之间的所有图画,而门票的价钱就是一张图画一元。
Sept 希望入场后可以看到所有名师的图画。当然,他想最小化购买门票的价格。
请求出他购买门票时应选择的 x,y,数据保证一定有解。
若存在多组解,输出 x 最小的那组。
输入格式
第一行两个整数 n,m,分别表示博览馆内的图画总数及这些图画是由多少位名师所绘画的。
第二行包含 n 个整数 ai,代表画第 i 幅画的名师的编号。
输出格式
一行两个整数 x,y。
输入输出样例
输入 #1复制
12 5
2 5 3 1 3 2 4 1 1 5 4 3
输出 #1复制
2 7
说明/提示
数据规模与约定
- 对于 30% 的数据,有 n≤200,m≤20。
- 对于 60% 的数据,有 n≤105,m≤103。
- 对于 100% 的数据,有 1≤n≤106,1≤ai≤m≤2×103。
实现代码:
cpp
#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],b[2005],k,ans,l,r,ll,rr;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
l=1; r=1; k=1; b[a[1]]=1; ans=1000005;
while(l<=r && r<=n)
{
if(k==m)
{
if(ans>r-l+1)
{
ans=r-l+1;
ll=l; rr=r;
}
b[a[l]]--;
if(b[a[l]]==0) k--;
l++;
}
else{
r++;
b[a[r]]++;
if(b[a[r]]==1) k++;
}
}
printf("%d %d",ll,rr);
return 0;
}
P1115 最大子段和
题目描述
给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。
输入格式
第一行是一个整数,表示序列的长度 n。
第二行有 n 个整数,第 i 个整数表示序列的第 i 个数字 ai。
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1复制
7
2 -4 3 -1 2 -4 3
输出 #1复制
4
说明/提示
样例 1 解释
选取 [3,5] 子段 {3,−1,2},其和为 4。
数据规模与约定
- 对于 40% 的数据,保证 n≤2×103。
- 对于 100% 的数据,保证 1≤n≤2×105,−104≤ai≤104。
2026/01/21:增加一组 hack 数据。
实现代码:
cpp
#include<bits/stdc++.h>
using namespace std;
int n,a[200020],b[200020],i,ans=-2147483647;
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
if(i==1) b[i]=a[i];
else b[i]=max(a[i],b[i-1]+a[i]);
ans=max(ans,b[i]);
}
cout<<ans;
return 0;
}
P7072 [CSP-J 2020] 直播获奖
题目描述
NOI2130 即将举行。为了增加观赏性,CCF 决定逐一评出每个选手的成绩,并直播即时的获奖分数线。本次竞赛的获奖率为 w%,即当前排名前 w% 的选手的最低成绩就是即时的分数线。
更具体地,若当前已评出了 p 个选手的成绩,则当前计划获奖人数为 max(1,⌊p×w%⌋),其中 w 是获奖百分比,⌊x⌋ 表示对 x 向下取整,max(x,y) 表示 x 和 y 中较大的数。如有选手成绩相同,则所有成绩并列的选手都能获奖,因此实际获奖人数可能比计划中多。
作为评测组的技术人员,请你帮 CCF 写一个直播程序。
输入格式
第一行有两个整数 n,w。分别代表选手总数与获奖率。
第二行有 n 个整数,依次代表逐一评出的选手成绩。
输出格式
只有一行,包含 n 个非负整数,依次代表选手成绩逐一评出后,即时的获奖分数线。相邻两个整数间用一个空格分隔。
输入输出样例
输入 #1复制
10 60
200 300 400 500 600 600 0 300 200 100
输出 #1复制
200 300 400 400 400 500 400 400 300 300
输入 #2复制
10 30
100 100 600 100 100 100 100 100 100 100
输出 #2复制
100 100 600 600 600 600 100 100 100 100
说明/提示
样例 1 解释

数据规模与约定
各测试点的 n 如下表:
| 测试点编号 | n= |
|---|---|
| 1∼3 | 10 |
| 4∼6 | 500 |
| 7∼10 | 2000 |
| 11∼17 | 104 |
| 18∼20 | 105 |
对于所有测试点,每个选手的成绩均为不超过 600 的非负整数,获奖百分比 w 是一个正整数且 1≤w≤99。
提示
在计算计划获奖人数时,如用浮点类型的变量(如 C/C++ 中的 float 、 double,Pascal 中的 real 、 double 、 extended 等)存储获奖比例 w%,则计算 5×60% 时的结果可能为 3.000001,也可能为 2.999999,向下取整后的结果不确定。因此,建议仅使用整型变量,以计算出准确值。
附件下载
live3.in74.50KB
live3.ans78.13KB
实现代码:
cpp
#include <bits/stdc++.h>
using namespace std;
priority_queue<int> ma_hp;
priority_queue<int, vector<int>, greater<int> > mi_hp;
int n, w, now, num;
void qwq()
{
if (mi_hp.size()<now)
{
mi_hp.push(ma_hp.top());
ma_hp.pop();
}
if (mi_hp.size() > now)
{
ma_hp.push(mi_hp.top());
mi_hp.pop();
}
}
void push(int num)
{
if (num >= ma_hp.top()) mi_hp.push(num);
else ma_hp.push(num);
qwq();
}
int main()
{
scanf("%d%d", &n, &w);
ma_hp.push(0);
for (int p = 1; p <= n; p++)
{
now=max(1,p*w/100);
scanf("%d", &num);
push(num);
printf("%d ", mi_hp.top());
}
return 0;
}
P2671 [NOIP 2015 普及组] 求和
题目背景
NOIP2015 普及组 T3
题目描述
一条狭长的纸带被均匀划分出了 n 个格子,格子编号从 1 到 n。每个格子上都染了一种颜色 colori(用 [1,m] 当中的一个整数表示),并且写了一个数字 numberi。
| 编号 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| 颜色和数字 | 5 | 5 | 3 | 2 | 2 | 2 |
定义一种特殊的三元组:(x,y,z),其中 x,y,z 都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
-
x,y,z 都是整数,x<y<z,y−x=z−y。
-
colorx=colorz。
满足上述条件的三元组的分数规定为 (x+z)×(numberx+numberz)。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以 10007 所得的余数即可。
输入格式
第一行是用一个空格隔开的两个正整数 n 和 m,n 表示纸带上格子的个数,m 表示纸带上颜色的种类数。
第二行有 n 用空格隔开的正整数,第 i 个数字表示纸带上编号为 i 格子上面写的数字 numberi。
第三行有 n 用空格隔开的正整数,第 i 数字表示纸带上编号为 i 格子染的颜色 colori。
输出格式
一个整数,表示所求的纸带分数除以 10007 所得的余数。
输入输出样例
输入 #1复制
6 2
5 5 3 2 2 2
2 2 1 1 2 1
输出 #1复制
82
输入 #2复制
15 4
5 10 8 2 2 2 9 9 7 7 5 6 4 2 4
2 2 3 3 4 3 3 2 4 4 4 4 1 1 1
输出 #2复制
1388
说明/提示
样例 1 解释
纸带如题目描述中的图所示。
所有满足条件的三元组为:(1,3,5),(4,5,6)。
所以纸带的分数为 (1+5)×(5+2)+(4+6)×(2+2)=42+40=82。
对于第 1 组至第 2 组数据, 1≤n≤100,1≤m≤5;
对于第 3 组至第 4 组数据,1≤n≤3000,1≤m≤100;
对于第 5 组至第 6 组数据,1≤n≤105,1≤m≤105,且不存在出现次数超过 20 的颜色;
对于全部 10 组数据,1≤n≤105,1≤m≤105,1≤colori≤m,1≤numberi≤105。
实现代码:
cpp
#include <cstdio>
const int N = 100000;
const int M = 10007;
int n, m;
int sum[N + 1][2], nt[N + 1][2];
int color[N + 1], number[N + 1];
long long ans = 0;
int main()
{
scanf(" %d %d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &number[i]);
number[i] %= M;
}
for(int i = 1; i <= n; i++) {
scanf("%d", &color[i]);
int c = color[i];
int g = i % 2;
nt[c][g]++;
sum[c][g] += number[i];
sum[c][g] %= M;
}
for(int i = 1; i <= n; i++) {
int c = color[i];
int g = i % 2;
ans += i % M * ((sum[c][g] + (nt[c][g] - 2) % M * number[i] + M) % M);
ans %= M;
}
printf("%lld", ans);
return 0;
}