E. Special Elements(前缀和+尺取)
题目传送门http://codeforces.com/problemset/problem/1352/E
#include<iostream>
#include<algorithm>
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn=1e4+10;
typedef long long ll;
int t,a[maxn],sum[maxn];
int vis[maxn];
int n;
bool Check(int x){ //尺取看是否元素满足题意
int l=1,r=2;
while(r <= n){
int t=sum[r]-sum[l-1];
if(t == x){
return true;
}
if(t > x) l++;
else r++;
if(l == r) r++;
}
return false;
}
int main()
{
ios;
cin>>t;
while(t--){
int cnt=0;
memset(vis,0,sizeof(vis));
memset(sum,0,sizeof(sum));
cin>>n;
for(int i=1 ; i<=n; i++){
cin>>a[i];
vis[a[i]]++;
sum[i]=sum[i-1]+a[i]; //定义前缀和数组
}
//cout<<vis[4]<<"\n";
for(int i=1;i<=n;i++){
if(!vis[a[i]]) continue;
else{
if(Check(a[i]))
cnt += vis[a[i]]; //用vis[]数组作为桶把元素装起来,一个元素符合,说明都符合
vis[a[i]]=0; //别忘了消除标记
}
}
cout<<cnt<<"\n";
}
}
P3406 海底高铁
P3406 海底高铁
差分,求出每段路走的次数,在用前缀和解出答案
#include<iostream>
using namespace std;
char ch;
template<class T>
inline void rd(T& x) {//快读不解释了哈
x = 0; int w = 1;
ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')w = -1; ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
x = x * w;
}
int a[100001]; unsigned long long t ,sum;
int main()
{
int n, m,x,y,z;
rd(n), rd(m);
rd(x);
for (int i = 2; i <= m; i++)
{
rd(y);//这个循环是安装路牌的过程
if (x < y)
{
a[x]++;
a[y]--;
}
else
{
a[x]--;
a[y]++;
}
x = y;
}
for (int i = 1; i < n; i++)
{
t += a[i];
rd(x),rd(y),rd(z);
sum += t * y + z < t * x ? t * y + z : t * x; //这一块决定是不是买卡
}
cout << sum;
return 0;
}
差分(着实有些简单)(Acwing797)
#include<iostream>
#include<algorithm>
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn=1e6+10;
typedef long long ll;
int a[maxn],ca[maxn],n,m;
void add(int l,int r,int c){
ca[l]+=c;
ca[r+1]-=c;
}
void Recover(){
ca[0]=0;
for(int i=1;i <= n;i++){
ca[i]+=ca[i-1];
}
}
int main()
{
a[0]=0;
ca[0]=0;
ios;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
ca[i]=a[i]-a[i-1];
}
int l,r,c;
while(m--){
cin>>l>>r>>c;
add(l,r,c);
}
Recover();
for(int i=1;i<=n;i++) cout<<ca[i]<<" ";
return 0;
}Acwing1270. 数列区间最大值
传送门
第一次做的时候不知道算法,暴力超时,现在看了大佬的题解才懂
我是用树状数组做的,其他解法还有好多算法我不会,准备这两天学
#include<iostream>
#include<algorithm>
int lowest_bit(int n) { return n & (-n); }
//求长度,例如i==8,等于 1000B ,则该数组单元包括了data[8]本身的数据,
//而二进制又有三个零,所以又包括了i之前的七个数据,加上本身的数据就是2^3 =8;
const int space = 1e6 + 7;
int ali[space] = {}, al[space] = {};//ali数组是保存树状数组的值,而al数组保存的是每个单元的数据
//若该题是求区间和的话,应该通过al数组来修改ali数组才行 --- 减去之前的数据,加上更改的数据
int N, M;
void updata(int pos, int data, int arr_len)
{
for (int i = pos; i <= arr_len; i += lowest_bit(i))
ali[i] = std::max(ali[i], data);
return;
}
int query(int left, int right)
{
int max_ans = -0x7f7f7f7f, i = right;
for (; i >= left && i - lowest_bit(i) + 1 >= left; i -= lowest_bit(i))//递推到头
max_ans = std::max(max_ans, ali[i]);
while (i >= left)//若i还是大于等于left则还没有枚举完成,继续枚举
{
max_ans = std::max(max_ans, al[i]);
if (i - lowest_bit(i) + 1 < left)i--;
else
{
max_ans = std::max(max_ans, ali[i]);
i -= lowest_bit(i);
}
}
return max_ans;
}
int main(void)
{
scanf("%d %d", &N, &M);
for (int i = 1; i <= N; i++)
{
scanf("%d", &al[i]);
updata(i, al[i], N);
}
while (M--)
{
int x, y;
scanf("%d %d", &x, &y);
printf("%d\n", query(x, y));
}
return 0;
}
京公网安备 11010502036488号