poj3320

转移自老blog

poj3320

链接

题意

        一本书有P页,每一页都一个知识点,求去最少的连续页数覆盖所有的知识点。
        p<1e6 

题解

        先考虑一个暴力做法,枚举所有的方案,此做法复杂度,n^2
        然后我们尝试dp,
        dp[i]代表页数[0:i]中以i结尾的,覆盖了所有的知识点的最大的页数起点
        显然 起点j --->  dp[i] j<i 
        容易证明:dp[i]关于i单调不减
        加速判断过程,可以map记录,也可以hash映射,
        然后我惊讶的发现此做法竟然就是尺取法。

牛客练习赛41B

转移自老blog

牛客练习赛41B

链接

题意

        有一个数字初值为0,n回合操作,每回合操作有两种,第一种操作将分数加上ai,第二种操作是将分数乘上-1.问有多少种操作方式在第n回合之后数字变为-666,而且中间每一个回合之后分数都不是666。
        n<300
        -666<ai<666

题解

        设:
        dp[i][j]为第i回合取得数字j,且不经过666,的方案数
        i<300
        300*-666<j<300*666
        可以滚动

计蒜客A2000

转移自老blog

计蒜客A2000

链接

题意

        一个圆环,每个位置可以选择2^k中任意一个数,要求相邻位置异或不等于pow(2,k−1),

题解

        a[i]表示到i位置首尾完全相同的合法链的方案数
        b[i]表示到i位置首尾完全相反的方案数,
        c[i]表示到i位置首尾既不完全相同也不完全相反的方案数

计蒜客A2012

转移自老blog

计蒜客A2012

链接

题意

        给你一串运算符和一个初始值,你要按顺序使用这些运算符与一个序列中的数进行运算,序列中数的个数大于运算符的个数,要按先后顺序使用这些数而运算符,当然也可以选择不用某个数,但最后一定要把所有运算符用光。 

题解

        mx[i][j]前i个运算符前j个数能得到的最大值,mi[i][j]前i个运算符前j个数能得到的最小值,

acm_head_file

转移自老blog

快速读入头

#include<bits/stdc++.h>
#define ll long long
using namespace std;
void read(ll& x)
{
    int f = 1;
    x = 0;
    char ch = getchar();
    
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    x *= f;
}

void read(int& x)
{
    int f = 1;
    x = 0;
    char ch = getchar();
    
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    x *= f;
}
///--------------head-----------------------------------------------------------------------------///
///--------------head-----------------------------------------------------------------------------///
///--------------head-----------------------------------------------------------------------------///
///--------------head-----------------------------------------------------------------------------///
///--------------head-----------------------------------------------------------------------------///
///--------------head-----------------------------------------------------------------------------///
///--------------head-----------------------------------------------------------------------------///
///--------------head-----------------------------------------------------刚好五十行----------------///

  
//究极读入挂
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}

2018焦作站

转移自老blog

2018焦作站

         焦作站,我们队拿到了第一个铜牌,可惜比赛进行的不是那么顺利。
         第一题签到题直接A了,第二题就比较难受了,据说在那时我们队排名最低掉到了两百四五十名,第二题接近两个小时才做出来,这是一个很大的遗憾,以至于后面的题目来不及做了,其实那题就是一个简单的递推关系,维护了一些额外的信息就行了。那题还是递推关系没有算仔细,那一类的题目其实我也就做过一两道,所以不熟练。第三题是一个卷积,积性函数卷恒等函数,卷出来还是积性函数,很明显的卷恒等函数的题目,因为不熟(嘲讽的是我们总结的题目里面有这一类题目的做法)所以直接忘了怎么做了,结果尹港爆发瞬间找到了规律。。。。。。我敲了个暴力验证了他的结论然后就A了,第四题计算几何,其实是个签到题。第五题图论搜索,bfs,裸的,不知道为什么tle,后来发现memset复杂度高,优化了之后还是tle,然后来不及改了,都怪第二题浪费了太多的时间,第二题明显最多最多40分钟可以A的,浪费了近一个小时,导致第五题来不及了。
         总的来说,现在铜牌银牌题目都会做了,可惜不熟练,有点慢。估计以后得练熟练度了。

2018牛客总结

转移自老blog 2018牛客总结

第一场

通过四题

两签到

两中等

目前赛后补三题

1.求解不定方程ax+by=c使得p2*x2+p1*x+q2*y2+q1*y最小

拓展欧几里得算法

二次函数的极值暴算

2.有个人要从一条直线走到另一条平行线,中间有几个圆,在直线和圆上走不消耗体力,其他消耗体力的与路程正比

计算几何及最短路模型转化

3.括号匹配,一个序列有很多很多不同括号,问你任意区间括号是否匹配

有两种做法,第一是记录括号入栈后栈顶元素

                      第二是根据括号唯一匹配,维护每个区间是否封闭匹配,即维护区间匹配对象的最值

4.构造一个矩阵使得每一行每一列都包含了所有的数字(1-N)且对于所有的 1 ≤ i < j ≤ n, 有 Ai,j ≠ Aj,i。

通过已有矩阵来构造未知矩阵

5.现有N个数a1,a2,...,aN。对于每一个ak,求有多少个有序二元组(i,j)满足,其中P为一给定质数。

根据原根性质将乘法转化为加法,再转化为fft

第二场

通过三题

签到两题

中等一题

目前赛后未补

1.计算一个矩阵与另一个01矩阵的积的所有元素的异或和

矩阵分块加速乘法,每八个元素预处理一次,乘时O1查询,共计加速八倍

 

第三场

通过两题

签到两题

赛后补四题

1.马走日

日了狗了

2.树上包含每个点的连通点集的数量

树上dp,两次dfs,第一次维护节点子孙数,第二次维护其他方向子孙数

第二次维护注意坑爹的逆元不存在情况

3.修修和栋栋轮流取石子,每人每次需要从任意一堆石子中取走个,修修先手。无法操作的人失败。此外,如果一个人取完了一堆石子,他会立即获胜。

sg函数,设定a-b是不可到达的状态,并发现循环节且特判a=1即可

4.二分图是否存在,不存在找奇环

一次dfs,或者镜像并查集+dfs

第四场

通过五题

五个签到题

第五场

通过一题

一个中等题

赛后补一题

1.中有多少不同的数,这些不同的数字里面第k大的是多少。

证明一下什么时候是2*sqrt(n)什么时候是2*sqrt(n)-1就行

2.an=m0an-1+m1an-2+c

蒙哥马利快速模乘 或者运气好的O1快速乘法

第六场

通过三题

三个找规律的题搞了半天

还用上了rmq二分。。。

第七场

通过三题

一签到

一中等找规律

一个模拟

1.记住log2的值,就可以做了

2.魔方展开

bzoj2655

转移自老blog

bzoj2655

此文更新于2019.6.5
一个序列a1,...,an是合法的,当且仅当:
长度为给定的n。
a1,...,an都是[1,A]中的整数。
a1,...,an互不相等。
一个序列的值定义为它里面所有数的乘积,即a1a2...an。
求所有不同合法序列的值的和。
两个序列不同当且仅当他们任意一位不一样。
输出答案对一个数mod取余的结果。
f(i,j)-> 前i个元素中最大值为j的方案的权的和
f(i,j)=f(i-1,j-1)*i*j+f(i,j-1)
用数学归纳法证明f(i,j)关于j是一个最高次为2*i的多项式
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll mod;

ll qpow(ll a,ll b,ll mod){
    ll ret=1;
    while(b){
        if(b&1ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}

// (mod%i)=== -mod/i*i
const int maxn=1200;
ll fac_inv[maxn]={1,1};
void inv_ini(){
    for(ll i=0,fac=1;i<maxn;i++,fac=fac*i%mod) {
        fac_inv[i]=qpow(fac,mod-2,mod);
    }
}

ll prepre[maxn],suf[maxn],*pre=prepre+1;
ll getval(ll *y,ll n,ll x){// O(n) n次多项式有n+1项 y[0]...y[n] -> y[x]
    pre[-1]=suf[n+1]=1;
    for(int i=0;i<=n;i++pre[i]=pre[i-1]*(x-i+mod)%mod;
    for(int i=n;i>=0;i--suf[i]=suf[i+1]*(i-x+mod)%mod;
    ll ret=0;
    for(int i=0;i<=n;i++) {
        ll up=pre[i-1]*suf[i+1]%mod;
        ll down=fac_inv[i]*fac_inv[n-i]%mod;
        ret=(ret+y[i]*up%mod*down)%mod;
    }
    return ret;
}

// f(i,j)-> 前i个元素中最大值为j的方案的权的和
// f(i,j)=f(i-1,j-1)*i*j+f(i,j-1)
// 用数学归纳法证明f(i,j)关于j是一个最高次为2*i的多项式
ll f[maxn][maxn*3];
int main(){
    ll n,a;
    while(~scanf("%lld%lld%lld",&a,&n,&mod)){
        inv_ini();
        for(ll j=1;j<=3*n;j++f[1][j]=(f[1][j-1]+j)%mod;
        for(ll i=2;i<=n;i++){
            for(ll j=i;j<=3*n;j++){
                f[i][j]=(i*j*f[i-1][j-1]+f[i][j-1])%mod;
            }
        }
        //we know f(n) f(n+1) ... f(3n)
        //if g(i)=f(i+n)
        // than f(a)=g(a-n)
        printf("%lld\n",getval(f[n]+n,2*n,(a-n+mod)%mod));
    }
}
此文标签
拉格朗日插值法

cf_566_div2_E

转移自老blog

cf_566_div2_E

此文更新于2019.6.13
题意:
    f(x)=c^(2x-6)f(x-1)f(x-2)f(x-3)
    输入f(1) f(2) f(3) n c
    输出f(n)
数据范围:
    f(1)<1e9
    f(2)<1e9
    f(3)<1e9
    c<1e9
    n<1e18
法1:
令g(x)=f(x)*c^x
则g(x)=g(x-1)g(x-2)g(x-3)
令h(x)=lg(5,g(x))
则h(x)=h(x-1)+h(x-2)+g(x-3)
于是成了bsgs算法+矩阵快速幂
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod=1e9+7;


struct Sarray{
    static const ll mod=1e9+6;
    static const ll LEN=3;
    ll len,data[LEN][LEN];

    Sarray(ll len,ll flag):len(len){
        for(ll i=0;i<len;i++){
            for(ll j=0;j<len;j++)data[i][j]=0;
            data[i][i]=flag;
        }
    }

    Sarray operator *(const Sarray&a){
        Sarray tem(a.len,0);
        for(ll i=0;i<len;i++){
            for(ll j=0;j<len;j++){
                for(ll k=0;k<len;k++){
                    tem.data[i][j]=(tem.data[i][j]+data[i][k]*a.data[k][j])%mod;
                }
            }
        }
        return tem;
    }

    Sarray operator +(const Sarray&a){
        Sarray tem(a.len,0);
        for(ll i=0;i<len;i++){
            for(ll j=0;j<len;j++){
                tem.data[i][j]=(data[i][j]+a.data[i][j])%mod;
            }
        }
        return tem;
    }
};

Sarray qpow(Sarray a,ll b){//会更改a,不能按引用传递
    Sarray tem(a.len,1);
    while(b){
        if(b&1)tem=a*tem;
        a=a*a;
        b>>=1;
    }
    return tem;
}

ll qpow(ll a,ll b){
    ll ret=1;
    while(b){
        if(b&1ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}


ll oria[3][3]={
        0,0,0,
        0,0,0,
        1,0,0
};

ll orib[3][3]={
        0,0,0,
        1,0,0,
        0,0,0
};

ll oric[3][3]={
        1,0,0,
        0,0,0,
        0,0,0
};

ll transs[3][3]={
        1,1,1,
        1,0,0,
        0,1,0
};

ll get(ll n,ll beg[3][3]){
    Sarray orn(3,1),trans(3,1);
    memcpy(orn.data,beg,sizeof(orn.data));
    memcpy(trans.data,transs,sizeof(trans.data));
    if(n==1return beg[2][0];
    if(n==2return beg[1][0];
    return (qpow(trans,n-3)*orn).data[0][0];
}

int  main(){
    ll n,f1,f2,f3,c;
    cin>>n>>f1>>f2>>f3>>c;
    ll g1=f1*c%mod;
    ll g2=f2*c%mod*c%mod;
    ll g3=f3*c%mod*c%mod*c%mod;

    ll A=get(n,oria);
    ll B=get(n,orib);
    ll C=get(n,oric);

    ll gn=qpow(g1,A)*qpow(g2,B)%mod*qpow(g3,C)%mod;
    ll t=qpow(c,n);
    cout<<gn*qpow(t,mod-2)%mod<<endl;

}

法2:
令g(x)=f(x)*c^x
则g(x)=g(x-1)g(x-2)g(x-3)
可以肯定出g(x)=g(1)^a*g(2)^b*g(3)*c
于是a,b,c都是x的函数
且a(x)=a(x-1)+a(x-2)+a(x-3) bc同理
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int LEN=3;

void sarray_cpy(int a[][LEN],int b[][LEN],int n){
    for(int i=0;i<n;i++){// a/b可以为同一个数组
        for(int j=0;j<n;j++b[i][j]=a[i][j];
    }
}

void sarray_mul(int a[][LEN],int b[][LEN],int ret[][LEN],int n,int mod){
    static int c[LEN][LEN];// a/b/ret可以为同一个数组
    for(int i=0;i<n;i++) {
        for(int j=0;j<n;j++){
            c[i][j]=0;
            for(int k=0;k<n;k++){
                c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%mod;
            }
        }
    }
    sarray_cpy(c,ret,n);
}

void sarray_qpow(int aa[][LEN],ll b,int ret[][LEN],int n,int mod){
    static int a[LEN][LEN];// aa ret可以为同一个数组
    sarray_cpy(aa,a,n);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++ret[i][j]=0;
        ret[i][i]=1;
    }
    while(b){
        if(b&1sarray_mul(ret,a,ret,n,mod);
        sarray_mul(a,a,a,n,mod);
        b>>=1;
    }
}

void sarray_add(int a[][LEN],int b[][LEN],int c[][LEN],int n,int mod){
    for(int i=0;i<n;i++){// a,b,c可以为同一个数组
        for(int j=0;j<n;j++){
            c[i][j]=(a[i][j]+b[i][j])%mod;
        }
    }
}

// a^0 a^1 a^2 a^3 ... a^b
void sarray_sum(int a[][LEN],ll b,int ret[][LEN],int n,int mod){
    static int tmp[LEN][LEN];
    if(b==0sarray_qpow(a,b,ret,n,mod);
    else{
        ll mid=(b-1)>>1;
        sarray_sum(a,mid,ret,n,mod);
        sarray_qpow(a,mid+1,tmp,n,mod);
        for(int i=0;i<n;i++tmp[i][i]=(tmp[i][i]+1)%mod;
        sarray_mul(ret,tmp,ret,n,mod);
        if((b&1)==0) {
            sarray_mul(ret,a,ret,n,mod);
            for(int i=0;i<n;i++ret[i][i]=(ret[i][i]+1)%mod;
        }
    }
}

int qpow(int a,int b,int mod){
    int ret=1;
    while(b){
        if(b&1)ret=1ll*ret*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return ret;
}

// a^x === b x=lg(a,b)
int bsgs_lg(int a,int b,int mod){
    map<int,int>mp;
    int sqr=sqrt(mod-1)+1;
    for(int i=0;i<sqr;i++mp[qpow(a,i,mod)]=i; // baby step
    for(int i=0;i<mod-1;i+=sqr){ // giant step
        int tp=1ll*b*qpow(a,mod-1-i,mod)%mod; // a^(-i)
        if(mp.find(tp)!=mp.end()) return i+mp[tp];
    }
    return -1;// error
}

int main(){
    const int mod=1e9+7;
    ll n;
    int f1,f2,f3,c;
    cin>>n>>f1>>f2>>f3>>c;
    int g1=1ll*f1*c%mod;
    int g2=1ll*f2*c%mod*c%mod;
    int g3=1ll*f3*c%mod*c%mod*c%mod;

    g1=bsgs_lg(5,g1,mod);
    g2=bsgs_lg(5,g2,mod);
    g3=bsgs_lg(5,g3,mod);
    // cout<

    int orn[LEN][LEN]={
            g3,0,0,
            g2,0,0,
            g1,0,0
    };

    int trans[LEN][LEN]={
            1,1,1,
            1,0,0,
            0,1,0
    };

    int ans[LEN][LEN],t;
    if(n==1t=g1;
    else if(n==2t=g2;
    else if(n==3t=g3;
    else {
        int ans1[LEN][LEN];
        int ans2[LEN][LEN];
        sarray_sum(trans,n-3,ans1,3,mod-1);
        sarray_mul(ans1,orn,ans1,3,mod-1);
        sarray_sum(trans,n-4,ans2,3,mod-1);
        sarray_mul(ans2,orn,ans2,3,mod-1);
        t=(ans1[0][0]-ans2[0][0]+mod-1)%(mod-1);

        // for(int i=0;i<3;i++)for(int j=0;j<3;j++)ans[i][j]=(ans1[i][j]-ans2[i][j]+mod)%mod;
        // sarray_mul(ans,orn,ans,3,mod-1);
        // t=ans[0][0];
    }
    int gn=qpow(5,t,mod);
    int inv=qpow(c,mod-1-n%(mod-1),mod);
    cout<<1ll*gn*inv%mod<<endl;

}


此文标签
bsgs 矩阵快速幂

cf_566_div2_F

转移自老blog

cf_566_div2_F

此文更新于2019.6.13
题意:
    f(x)=abs(sin((p/q)*PI*x)) a<=x<=b
    输入 p q a b
    输出f(x)取最大值时候的x
数据范围:
    0<=a<=b<=1e9
    1<=p,q<=1e9
最后等价于求[a,b]间的x使得(2px)%(2q) 和q最接近
让x=m+kn , k=sqrt(b-a)
枚举n二分m即可
#include<bits/stdc++.h>
using namespace std;

//
// | sin(px/qpi) |
//
// (px/q)%1 -> 1/2
//
// (2px)%(2q) -> q



typedef long long ll;
const ll maxn=3e4+55;
struct node{
    ll x,gx;
    bool operator<(const node&rhsconst {
        if(gx!=rhs.gxreturn gx<rhs.gx;
        else return x<gx;
    }
}g[maxn];

ll get(ll p,ll q,ll x){
    return 2*p*x%(2*q);
}
ll dis(ll p,ll q,ll x){
    return abs(get(p,q,x)-q);
}
void update(ll&ans,ll cur,ll p,ll q){
    if(ans==-1ans=cur;
    else if(dis(p,q,cur)<dis(p,q,ans)) ans=cur;
    else if(dis(p,q,cur)==dis(p,q,ans)) ans=min(ans,cur);
}
int main(){
    ll n;
    cin>>n;
    while(n--){
        ll a,b,p,q;
        cin>>a>>b>>p>>q;
        ll k=10000;
        map<int,intmp;
        for(ll i=k-1;i>=0;i--mp[get(p,q,i)]=i;//g[i]=node{i,get(p,q,i)};
        ll sz=0;
        for(auto x:mpg[sz++]=node{x.second,x.first};

        ll bg=a,ans=-1;
        while(bg+k-1<=b){
            ll base=get(p,q,bg), idx;
            if(base<=qidx=lower_bound(g,g+sz,node{-1,q-base})-g;
            else idx=lower_bound(g,g+sz,node{-1,3*q-base})-g;

            update(ans,bg+g[idx%sz].x,p,q);
            update(ans,bg+g[(idx-1+sz)%sz].x,p,q);
            bg+=k;
        }
        if(bg<=b){
            for(ll i=bg;i<=b;i++update(ans,i,p,q);
        }
        cout<<ans<<endl;
    }
}
此文标签
bsgs