Luogu P1625 求和
阿新 • • 發佈:2020-10-12
題意
給定兩個整數 \(n,m\),求
\[\sum\limits_{i=1}^{n}\frac{1}{\prod\limits_{j=i}^{i+m-1}j} \]\(\texttt{Data Range:}1\leq n+m\leq 500\)
題解
小學奧數,裂項相消。
比如說有如下例子:
\[\frac{1}{1\times2\times3}=\frac{1}{2}\left(\frac{1}{1\times2}-\frac{1}{2\times 3}\right) \]考慮以這個作為範例來 generalize 一下
\[\frac{1}{\prod\limits_{j=i}^{i+m-1}j}=\frac{1}{m-1}\left(\frac{1}{\prod\limits_{j=i}^{i+m-2}j}-\frac{1}{\prod\limits_{j=i+1}^{i+m-1}j}\right) \]然後求和就好了,注意到右邊是疊縮求和,直接用最後一項減去第一項即可。
\[\sum\limits_{i=1}^{n}\frac{1}{\prod\limits_{j=i}^{i+m-1}j}=\frac{1}{m-1}\sum\limits_{i=1}^{n}\left(\frac{1}{\prod\limits_{j=i}^{i+m-2}j}-\frac{1}{\prod\limits_{j=i+1}^{i+m-1}j}\right)=\frac{1}{m-1}\left(\frac{1}{\prod\limits_{j=1}^{m-1}j}-\frac{1}{\prod\limits_{j=n+1}^{n+m-1}j}\right) \]接下來考慮如何不寫高精除高精來通過這個題。
顯然括號內的東西通分是可以靠分子分母的質因數分解形式的。
於是只要先算出括號內分子分母的質因數分解形式,再用高精乘算出實際分子,減去 \(1\) 之後再質因數分解。最後分子分母抵掉就好了。
所以這個時候只需要考慮高精除低精和高精模低精兩個操作就好了。
程式碼
#include<bits/stdc++.h> using namespace std; typedef int ll; typedef long long int li; const ll MAXN=2e5+51,BASE=1000000000; const li BASE2=(li)BASE*BASE; struct BigInt{ vector<ll>v; ll neg; BigInt(); BigInt(const string &x); BigInt(const char *x); BigInt(ll x); BigInt(li x); BigInt(const BigInt &x); inline void setup(); inline void setupStr(const char *str); inline BigInt& reduce(); inline ll isZero()const; inline string toString()const; inline void op()const; inline BigInt &operator =(const string &x); inline BigInt &operator =(const char *x); inline BigInt &operator =(ll x); inline BigInt &operator =(li x); inline BigInt &operator =(const BigInt &x); inline ll compareAbs(const BigInt &x)const; }; ll n,m,c; BigInt f,g; ll fn[MAXN],fd[MAXN]; inline ll read() { register ll num=0,neg=1; register char ch=getchar(); while(!isdigit(ch)&&ch!='-') { ch=getchar(); } if(ch=='-') { neg=-1; ch=getchar(); } while(isdigit(ch)) { num=(num<<3)+(num<<1)+(ch-'0'); ch=getchar(); } return num*neg; } inline void BigInt::setup() { neg=0,v.clear(),v.push_back(0); } inline void BigInt::setupStr(const char *str) { ll len; char token[10]; setup(),len=strlen(str),*str=='-'?neg=1,++str,--len:1,token[9]=0; if(!len||(len==1&&*str=='0')) { return (void)(neg=0); } v.clear(); for(register int i=1;i*9<=len;i++) { memcpy(token,str+(len-i*9),9),v.push_back((ll)(strtol(token,NULL,10))); } if(len%9) { memcpy(token,str,len%9),token[len%9]=0; v.push_back((ll)(strtol(token,NULL,10))); } reduce(); } inline ll BigInt::isZero()const { return v.size()==1&&!v.back(); } inline BigInt& BigInt::reduce() { while(v.size()>1&&!v.back()) { v.pop_back(); } return isZero()?neg=0:1,*this; } inline string BigInt::toString()const { string res; char token[10]; ll c=v.size()-1; neg&&!this->isZero()?res.push_back('-'):(void)1; for(sprintf(token,"%d",v[c]);res+=token,c--;sprintf(token,"%09d",v[c])); return res; } inline void BigInt::op()const { return (void)(cout<<this->toString()); } BigInt::BigInt() { setup(); } BigInt::BigInt(const string &x) { this->setupStr(x.c_str()); } BigInt::BigInt(const char *x) { this->setupStr(x); } BigInt::BigInt(ll x) { setup(),x<0?(neg=1,x=-x):1,v.back()=x%BASE; x>=BASE?v.push_back(x/BASE):(void)1; } BigInt::BigInt(li x) { setup(),x<0?(neg=1,x-=x):1,v.back()=x%BASE; x>=BASE?v.push_back(x/BASE%BASE):(void)1; x>=BASE2?v.push_back(x%BASE2):(void)1; } BigInt::BigInt(const BigInt &x) { neg=x.neg,v=x.v; } inline BigInt& BigInt::operator =(const string &x) { return this->setupStr(x.c_str()),*this; } inline BigInt& BigInt::operator =(const char *x) { return this->setupStr(x),*this; } inline BigInt& BigInt::operator =(ll x) { setup(),x<0?(neg=1,x=-x):1,v.back()=x%BASE; return x>=BASE?v.push_back(x/BASE):(void)1,*this; } inline BigInt& BigInt::operator =(li x) { setup(),x<0?(neg=1,x=-x):1,v.back()=x%BASE; x>=BASE?v.push_back(x/BASE%BASE):(void)1; return x>=BASE2?v.push_back(x%BASE2):(void)1,*this; } inline BigInt& BigInt::operator =(const BigInt &x) { neg=x.neg,v=x.v,*this; } inline ll BigInt::compareAbs(const BigInt &x)const { if(v.size()!=x.v.size()) { return (v.size()<x.v.size())?-1:1; } for(register int i=v.size()-1;i>=0;i--) { if(v[i]!=x.v[i]) { return (v[i]<x.v[i])?-1:1; } } return 0; } inline BigInt unsignedAdd(BigInt &x,BigInt &y) { BigInt res; ll mx=max(x.v.size(),y.v.size()),carry=0; x.v.resize(mx+1),y.v.resize(mx+1),res.v.resize(mx+1); for(register int i=0;i<=mx;i++) { (res.v[i]=x.v[i]+y.v[i]+carry)>=BASE?res.v[i]-=BASE,carry=1:carry=0; } return x.reduce(),y.reduce(),res.reduce(); } inline BigInt unsignedSub(BigInt &x,BigInt &y) { BigInt res; ll mx=max(x.v.size(),y.v.size()),carry=0; x.v.resize(mx+1),y.v.resize(mx+1),res.v.resize(mx+1); for(register int i=0;i<=mx;i++) { (res.v[i]=x.v[i]-y.v[i]+carry)<0?res.v[i]+=BASE,carry=-1:carry=0; } return x.reduce(),y.reduce(),res.reduce(); } inline BigInt operator +(BigInt x,BigInt y) { BigInt res; res=x.neg==y.neg?unsignedAdd(x,y):unsignedSub(x,y); return res.neg=x.neg!=y.neg?(x.compareAbs(y)>=0?x.neg:y.neg):x.neg,res; } inline BigInt operator +=(BigInt &x,BigInt y) { return x=x+y,x; } inline BigInt operator -(BigInt x,BigInt y) { BigInt res; res=x.neg==y.neg?unsignedSub(x,y):unsignedAdd(x,y); return res.neg=x.neg==y.neg?(x.compareAbs(y)>=0?x.neg:y.neg):x.neg,res; } inline BigInt operator -=(BigInt &x,BigInt y) { return x=x-y,x; } inline BigInt operator *(BigInt x,ll u) { BigInt res; ll mx=x.v.size(),carry=0; x.v.resize(mx+1),res.v.resize(mx+1),res.neg=x.neg,u<0?res.neg^=1,u=-u:1; for(register int i=0;i<=mx;i++) { res.v[i]=((li)x.v[i]*u+carry)%BASE,carry=((li)x.v[i]*u+carry)/BASE; } return x.reduce(),res.reduce(); } inline BigInt operator *(BigInt x,BigInt y) { if(x.isZero()||y.isZero()) { return BigInt(); } BigInt res; ll n=x.v.size(),m=y.v.size(),j,k; li cur=0,carry=0; res.neg=x.neg^y.neg,res.v.resize(n+m); for(register int i=0;i<n+m;i++) { for(i<m?(j=0,k=i):(j=i-m+1,k=m-1);j<n&&k>=0;j++,k--) { cur+=(li)x.v[j]*y.v[k],carry+=cur/BASE,cur%=BASE; } res.v[i]=cur,cur=carry%BASE,carry/=BASE; } return res.reduce(); } inline BigInt operator /(BigInt x,ll u) { BigInt res; li cur=0; res.neg=x.neg,u<0?res.neg^=1,u=-u:1,res.v.resize(x.v.size()+1); for(register int i=x.v.size()-1;i>=0;i--) { cur=cur*BASE+x.v[i],cur-=(li)(res.v[i]=cur/u)*u; } return res.reduce(); } inline li operator %(BigInt x,ll u) { li cur=0; for(register int i=x.v.size()-1;i>=0;i--) { cur=cur*BASE+x.v[i],cur-=(li)(cur/u)*u; } return cur; } inline BigInt qpow(BigInt base,ll exponent) { BigInt res=1; while(exponent) { if(exponent&1) { res=res*base; } base=base*base,exponent>>=1; } return res; } int main() { n=read(),m=read(),f=g=1; for(register int i=n+1;i<=n+m-1;i++) { c=i; for(register int j=2;j<=sqrt(c);j++) { while(c%j==0) { fd[j]++,fn[j]++,c/=j; } } c!=1?fd[c]++,fn[c]++:1; } for(register int i=1;i<=m-1;i++) { c=i; for(register int j=2;j<=sqrt(c);j++) { while(c%j==0) { fn[j]--,c/=j; } } c!=1?fn[c]--:1; } for(register int i=1;i<=501;i++) { f=f*qpow(i,fn[i]),fn[i]=0; } f=f-1,fd[m-1]++; for(register int i=2;i<=501;i++) { while(f%i==0) { fn[i]++,f=f/i; } } for(register int i=1;i<=501;i++) { if(fd[i]>fn[i]) { g=g*qpow(i,fd[i]-fn[i]); } if(fn[i]>fd[i]) { f=f*qpow(i,fn[i]-fd[i]); } } f.op(),puts(""),g.op(); }