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