一次函数(好难的一次函数)
一次函数
(fx.c/cpp/pas)
【题目描述】
fqk 退役后开始补习文化课啦, 于是他打开了数学必修一开始复习
函数, 他回想起了一次函数都是 b kx x f ) ( 的形式, 现在他给了你 n 个
一次函数
i i i
b x k x f ) ( , 然后将给你 m 个操作, 操作将以如下格式给出:
M . 1 i k b ,把第 i 个函数改为 b kx x f i ) ( 。
Q . 2 l r x ,询问 ))) ( (... (
1
x f f f
l r r
mod 1000000007 的值。
【输入格式】
第一行两个整数 n , m ,代表一次函数的数量和操作的数量。
接下来 n 行,每行两个整数,表示
i
k ,
i
b 。
接下来 m 行,每行的格式为 M i k b 或 Q l r x 。
【输出格式】
对于每个操作 Q ,输出一行表示答案。
【输入样例】
5 5
4 2
3 6
5 7
2 6
7 5
Q 1 5 1
Q 3 3 2
M 3 10 6
Q 1 4 3
Q 3 4 4
【输出样例】
1825
17
978
98
【数据范围】
对于 % 30 的数据, 1000 , m n 。
对于 % 100 的数据, 1000000007 , , , 200000 , x b k m n 。
【时空限制】
对于每个测试点,时间限制为 s 2 ,空间限制为 MB 512 。
思路:
刚开始先看数据范围(好习惯)
发现这是个暴力过不了的题
于是开始边推公式边码代码
推了一个小时公式终于推了出来
但是爆零了!
因为这个题里有一个mod条件
大于这个mod值就必须被mod
但是我的公式里有用到除法
所以就被整数不能被零除这种错误给RE了
最后还是ylf大神讲的思路
正解是线段树
题目里的操作M和Q正符合线段树的单点修改和区间查询
所以我开始着手写线段树
线段树要维护两个值
hyxzc告诉我要用数组比结构体要快
但是我还是用的结构体
在维护线段树的值得时候
维护k和b
具体是这样维护的
k2*(k1*x+b1)+b2
可以化成这种形式
k2*k1*x+k2*b1+b2
这样我们就可以得到新的值
k3=k2*k1,b3=k2*b1+b2
k3,b3就是一个小区间的值
这样我们就可以推出l到r的k于b
来,上代码:
#include<cmath> #include<cstdio> #include<iostream> #define mod 1000000007 using namespace std; struct node { long long int l,r,kl,b; }; struct node tree[10000001],cur; long long int n,m,jkl,ll,rr,dis; char ch,ch1; void qread(long long int &x) { x=0,jkl=1;ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-') jkl=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+(int)(ch-'0');ch=getchar();} x*=jkl; } void tree_up(long long int k) { tree[k].kl=(tree[k<<1].kl*tree[k<<1|1].kl)%mod; tree[k].b=((tree[k<<1].b*tree[k<<1|1].kl)%mod+tree[k<<1|1].b)%mod; } void tree_build(long long int k,long long int l,long long int r) { tree[k].l=l,tree[k].r=r; if(l==r) { qread(tree[k].kl),qread(tree[k].b); return ; } long long int mid=(l+r)>>1; tree_build(k<<1,l,mid),tree_build(k<<1|1,mid+1,r); tree_up(k); } void tree_change(long long int k,long long int to,long long int nk,long long int nb) { if(tree[k].l==tree[k].r&&tree[k].l==to) { tree[k].kl=nk,tree[k].b=nb; return ; } long long int mid=(tree[k].l+tree[k].r)>>1; if(to<=mid) tree_change(k<<1,to,nk,nb); else tree_change(k<<1|1,to,nk,nb); tree_up(k); } struct node tree_sum(long long int k,long long int l,long long int r) { if(l==tree[k].l&&r==tree[k].r) return tree[k]; long long int mid=(tree[k].l+tree[k].r)>>1; if(l>mid) return tree_sum(k<<1|1,l,r); else if(r<=mid) return tree_sum(k<<1,l,r); else { struct node now1,now2; now1=tree_sum(k<<1,l,mid); now2=tree_sum(k<<1|1,mid+1,r); now1.b=((now2.kl*now1.b)%mod+now2.b)%mod; now1.kl=(now1.kl*now2.kl)%mod; return now1; } } int main() { qread(n),qread(m); tree_build(1,1,n); for(long long int i=1;i<=m;i++) { //scanf("%c %lld%lld%lld",&ch1,&ll,&rr,&dis); scanf("%c ",&ch1); qread(ll),qread(rr),qread(dis); if(ch1=='M') tree_change(1,ll,rr,dis); else { cur=tree_sum(1,ll,rr); dis=((dis*cur.kl)%mod+cur.b)%mod; cout<<dis<<endl; } } return 0; }
附,祭奠我那逝去的公式=.=
:
#include<cstdio> #include<cstdlib> #include<iostream> #define mod 1000000007 using namespace std; struct node { long long int k,b; }; struct node function[2000002]; long long int n,m,jkl,l,r,dis,cur,kol; long long int sumk[2000002],sumb[2000002],sumbb[2000002]; char ch,ch1; bool ok=false; void qread(long long int &x) { x=0,jkl=1;ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-') jkl=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+(int)(ch-'0');ch=getchar();} x*=jkl; } void change() { for(long long int j=1;j<=n;j++) { sumk[j]=(sumk[j-1]*function[j].k)%mod; //sumb[j]=((sumb[i-1]*function[i].k)%mod+function[i].b)%mod; } for(long long int j=1;j<=n;j++) { sumb[j]=(((function[j].b*sumk[n])%mod)/sumk[j])%mod; sumbb[j]=sumbb[j-1]+sumb[j]; } ok=false; } int main() { sumk[0]=1; qread(n),qread(m); sumk[n+1]=1; for(long long int i=1;i<=n;i++) { qread(function[i].k),qread(function[i].b); sumk[i]=(sumk[i-1]*function[i].k)%mod; //sumb[i]=((sumb[i-1]*function[i].k)%mod+function[i].b)%mod; sumb[i]=function[i].b; } for(long long int i=1;i<=n;i++) { sumb[i]=(((sumb[i]*sumk[n])%mod)/sumk[i])%mod; sumbb[i]=sumbb[i-1]+sumb[i]; } for(long long int i=1;i<=m;i++) { scanf("%c",&ch1),qread(l),qread(r),qread(dis); //cout<<l<<" "<<r<<" "<<dis<<" "<<endl; if(ch1=='M') { function[l].k=r,function[l].b=dis,ok=true; /*for(long long int j=1;j<=n;j++) { sumk[j]=(sumk[j-1]*function[j].k)%mod; //sumb[j]=((sumb[i-1]*function[i].k)%mod+function[i].b)%mod; } for(long long int j=1;j<=n;j++) { sumb[j]=(((function[j].b*sumk[n])%mod)/sumk[j])%mod; sumbb[j]=sumbb[j-1]+sumb[j]; }*/ } else { if(ok) change(); cur=dis; cur=((cur*sumk[r]%mod)/sumk[l-1])%mod; //cout<<cur<<endl; //kol=(sumb[r]-sumb[l-1]); /*if(sumk[n]/sumk[r]==0){ cout<<n<<" "<<r<<endl; cout<<sumk[n]<<" "<<sumk[r]<<endl; system("pause"); }*/ kol=((sumbb[r]-sumbb[l-1])/(sumk[n]/sumk[r])); //cout<<n<<" "<<r<<endl; //cout<<sumk[n]<<" "<<sumk[r]<<endl; //cout<<sumk[n]/sumk[r]<<endl<<(sumbb[r]-sumbb[l-1])<<endl<<kol<<endl; cur=(cur+kol)%mod; cout<<cur<<endl; } } return 0; }