泛刷水题记17.12.22

来源:互联网 发布:python爬虫开发 编辑:程序博客网 时间:2024/05/29 00:33

目前处于康复期,所以做多一点题目……感觉自己码力退步了QAQ连初二的时候都比不上了(现在连LCT都写不动了……颓颓颓)

LOJ 2038 「SHOI2015」超能粒子炮・改

题意:求i=0k(ni)(mod2333),其中n,k1018
分析:一般组合数取模的题目我们都可以马上想到Lucas定理,而这题我们稍微转化下就可以了
题解:先化一波式子,由于2333是质数,那么原式即

S(n,k)=i=0k(ni)(mod2333)

=i=0k(n/2333i/2333)(n%2333i%2333)(mod2333)

然后i%2333有一个模运算的周期性,同时这里面i/2333又是相等的,我们考虑分块处理,只需要考虑再考虑最后不单独成一块的那一部分,暴力即可
成整块的前一部分是i=0k23331(n/2333i)×i=02332(n%2333i)
然后剩下来的就是i=0k%2333(n/2333i/2333)(n%2333k%2333)
我们将S(n,k)代进去,得到
S(n,k)=S(n/2333,k23331)×S(n%2333,2332)+S(n%2333,k%2333)(n/2333k/2333)
同时预处理下12333范围内的组合数,利用Lucas递归到2333范围里面,而S(n,k)2333范围内预处理,大范围递归计算就好了,复杂度类似Lucas定理,为O(log2n)

# include <cstdio>using namespace std;const int mod = 2333;int c[mod+20][mod+20], f[mod+20][mod+20];inline int lucas(long long i, long long j){    if (i < mod && j < mod) return c[i][j];    return c[i%mod][j%mod]*lucas(i/mod, j/mod)%mod;}inline int calcCsum(long long i, long long j){    if (i < mod && j < mod) return f[i][j];    return (f[i%mod][mod-1]*calcCsum(i/mod, (j+1)/mod-1)+lucas(i/mod, j/mod)*f[i%mod][(j+1)%mod-1])%mod;}int main(){    c[0][0] = 1;    for (int i = 1; i < mod; i++)        for (int j = 0; j <= i; j++)            c[i][j] = (c[i-1][j]+(j>=1)*c[i-1][j-1])%mod;    for (int i = 0; i < mod; i++) {        f[i][0] = 1;        for (int j = 1; j < mod; j++)            f[i][j] = (f[i][j-1]+c[i][j])%mod;    }    int T; scanf("%d", &T);    while (T--) {        long long n, m;        scanf("%lld%lld", &n, &m);        printf("%d\n", calcCsum(n, m));    }    return 0;}

LOJ2028 「SHOI2016」随机序列

题意:一个序列ai,两个相邻数之间可以插入加号、减号或乘号,每次不断修改其中某个数并询问所有可能的表达式的和
分析:先考虑没修改怎么做,考虑一个DP,设f(i)表示前i个数能组成的表达式的和,g(i)表示方案数,那么插入一个加号和减号就直接乘方案数,插入乘号的话考虑往前j个是乘号,那么从f(ij)转移,再前一个是加号和减号分别讨论即可
但是这是第一眼想的思路,稍微再想想我们会发现这好像想多了……每一个加号都会有一个减号消掉他,所以只有第一个是有贡献的,那么就是剩下的方案数和前面的乘积和,即i=1n2×3nij=1iaj
一开始可以暴力统计一遍,然后每次修改可以直接用逆元把后面的给做掉,相当于后面的区间乘一个数,用线段树维护前缀乘积就好了
code没调,先存着

# include <cstido># define M 1000000007# define ms(x) (x>=mod?x-mod:x)using namespace std;namespace SegT{    int sum[S],tag[S];    inline void pup(int x){ sum[x]=ms(sum[x<<1]+sum[x<<1|1]); }    inline void ptg(int x,int d){ sum[x]=(sum[x]*d)%mod; }    inline void pdn(int x){ if (tag[x]!=1) ptg(x<<1,tag[x]),ptg(x<<1|1,tag[x]); tag[x]=1;  }    void init(int x,int l,int r){        if (l==r){ sum[x]=p[l]*a[l]; tag[x]=1; return; }        if (l<r){            tag[x]=1;            int m = (l+r)>>1;            init(x<<1,l,m),init(x<<1|1,m+1,r);            pup(x);        }    }    int opt,opans,opl,opr,opg;    void tend(int x,int l,int r){        if (opl <= l && r <= opr){      //in intervals            if (opt == 1){ opans = ms(opans+sum[x]*tag[x]); }            if (opt == 2){ tag[x]=(tag[x]*opg)%mod; }        }        else{            int m=(l+r)>>1; pdn(x);            if (opl <= m) tend(x<<1,l,m);            if (opr > m)  tend(x<<1|1,m+1,r);            pup(x);        }    }}int a[N],n,q;int main(){    scanf("%d%d",&n,&q);    for (int i=1;i<=n;++i) scanf("%d",a+i);    for (int i=2;i<=n;++i) a[i] = (a[i] * a[i-1]) % mod;    p[n]=2; for (int i=1;i<n;++i) p[i]=ms(p[i+1]+ms(p[i+1]+p[i+1]));    SegT::init(1,1,n);    for (int i=0;i<q;++i){        int t,v; scanf("%d%d",&t,&v);        SegT::opt=2; SegT::opl=SegT::opr=t; SegT::opg=v;        SegT::tend(1,1,n);        SegT::opt=1; SegT::opl=1,SegT::opr=n; SegT::opans=0;        SegT::tend(1,1,n);        printf("%d\n",SegT::opans);    }    return 0;}

「CodePlus 2017 12 月赛」可做题2

题意:问对于第一项是给定的i,第二项x[l,r]内,以此构成的Fibonacci数列里指定的第k项有多少种情况在模p意义下为m
分析:第一眼,发现这里中间Fibonacci的转移矩阵是相同的!于是可以直接快速幂求出Fk=a11i+a12x,然后我们再推推式子就是ma11ia12x(modp),用扩欧解一下a12+pk=ma11i就好了,实现上有不少坑点,例如i需要模p……另外需要注意ma11i有可能小于0,需要搞回来
另外还有Fibonacci数列取模循环节的方法,这里就暂且不提了

# include <cstring># include <iostream># include <cstdio># include <cmath># define mem(x,v) memset(x,v,sizeof(x))# define ms(x) (x>=p?x-p:x)using namespace std;typedef long long LL;LL i,l,r,k,p,m;struct matrix{    LL a[2][2];    matrix(){ mem(a,0); }    matrix operator*(const matrix t){        matrix ans;        for (int i=0;i<2;++i)            for (int j=0;j<2;++j)                for (int k=0;k<2;++k)                    ans.a[i][j]=(ans.a[i][j]+(a[i][k]*t.a[k][j])%p)%p;        return ans;    }    void print(){        cerr << a[0][0] <<' ' << a[0][1] << endl;        cerr << a[1][0] <<' ' << a[1][1] << endl;    }}; matrix fast_pow(matrix x,LL k){    matrix t; t.a[0][0]=t.a[1][1]=1;    for ( ;k;k>>=1,x=x*x) if (k&1) t=t*x;    return t;}void extgcd(LL a,LL b,LL&d,LL &x,LL &y){    if(!b){d=a;x=1,y=0;}    else{        extgcd(b,a%b,d,y,x);        y-=x*(a/b);    }}int main(){//  freopen("inp.in","r",stdin);//  freopen("myp.out","w",stdout);    matrix fib; fib.a[0][1]=fib.a[1][0]=fib.a[1][1]=1;    int T; cin >> T;    while (T--){        cin >> i >> l >> r >> k >> p >> m;        i%=p;        matrix t=fast_pow(fib,k-1); //t.print(); cout << endl;    //  swap(t.a[0][1],t.a[0][0]) ;        LL d,k,a2; extgcd(p,t.a[0][1],d,k,a2);        LL c=(m - t.a[0][0]*i);        if (c < 0){ c = p - ((-c) % p); }        if(c % d != 0) cout << 0 << endl;        else{            //a2+pk=21 ?             a2 *= c/d; k*= c/d;            a2 += ((l-a2) / (p/d)) * (p / d);            while (a2 > l){ a2 -= p/d; }            while (a2 < l){ if (a2 > r){cout << 0 << endl; continue;} a2 += p/d; }        //  cerr << "Now l=" << l <<"  now a2=" << a2 << " now spa = " << p << '/' << d << endl;        //  cerr << (r-a2) << "\n" << (p/d) << endl;            LL num = (((r-a2) / (p/d))+1); cout << (r>=a2?num:0) << endl;        }    }    return 0;}
原创粉丝点击