算法1:暴力(30分)
观察到30%的评测用例,不会做的可以暴力骗30分。
#include <iostream>
using namespace std;
const int N= 1010;
int n,m;
int a[N];
void div(int l,int r,int v)
{
for(int i = l;i <= r;i ++ )
{
if(a[i] % v == 0) a[i] /= v;
}
}
int sum(int l,int r)
{
int res = 0;
for(int i=l;i <= r;i ++) res += a[i];
return res;
}
int main()
{
cin >> n >> m;
for(int i=1;i<=n;i++)cin >> a[i];
while(m -- )
{
int op,l,r,v;
cin >> op;
if(op == 1){
cin >> l >> r >> v;
div(l,r,v);
}
else
{
cin >> l >> r;
cout << sum(l,r)<<endl;
}
}
return 0;
}
算法2:树状数组(100分)
裸题,树状数组可以做单点修改和区间查询。对于op == 1的情况,是区间修改,但可以通过遍历符合单点修改。
// 树状数组的核心操作
int lowbit(int x)
{
return x & -x;
}
LL sum(int x) // 区间求和
{
LL res = 0;
for(int i=x;i;i -= lowbit(i)) res += tr[i];
return res;
}
void update(int x,int c) // 单点修改,减一个数可以看成加相反数!
{
for(int i=x;i<=n;i+=lowbit(i)) tr[i] += c;
}
#include <cstdio>
using namespace std;
const int N= 100010;
typedef long long LL;
int n,m;
int a[N];
LL tr[N];
int lowbit(int x)
{
return x & -x;
}
LL sum(int x) // 区间求和
{
LL res = 0;
for(int i=x;i;i -= lowbit(i)) res += tr[i];
return res;
}
void update(int x,int c) // 单点修改,减一个数可以看成加相反数!
{
for(int i=x;i<=n;i+=lowbit(i)) tr[i] += c;
}
int main()
{
//cin >> n >> m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
//cin >> a[i];
scanf("%d",&a[i]);
update(i,a[i]);
}
while(m -- )
{
int op,l,r,v;
//cin >> op;
scanf("%d",&op);
if(op == 1){
//cin >> l >> r >> v;
scanf("%d%d%d",&l,&r,&v);
if(v == 1) continue; // 优化1,不加这个优化,超时,50分
for(int i = l;i <= r;i ++)
{
if(a[i] >= v && a[i] % v == 0) // 优化2,避免出现a[i] == 0的情况,
// 不加这个优化,超时,50分,果然最后一题很多坑!
{
update(i,-(a[i] - a[i] / v)); // 这里树状数组做单点修改和区间查询
a[i] /= v; // 忘记这里也要修改a[]数组 // 单点修改需要遍历
}
}
}
else
{
//cin >> l >> r;
scanf("%d%d",&l,&r);
//cout << sum(r) - sum(l - 1) <<endl;
printf("%lld\n",sum(r)- sum(l - 1));
}
}
return 0;
}
算法3:线段树(?)
线段树也可以完成区间问题,且比树状数组更强大。就是代码难写。
不会,等学会了线段树再补吧。