SNOI2017题解

bzoj突然有了snoi的题,就把以前做过的拷过去好了,所以重新做一下写一个题解好了。

DAY1 T1
求一个数列: A1=1,An=Sn+nk n1018,k10

关于之前的sum的式子都可以化为一个前缀和式 f[i]=2f[i1]+nk
于是我们构造一个k+2唯矩阵表示答案和 i 0k次幂。
然后我们用二项式定理来推算 (n+1)k=kr=0Crknkr

时间复杂度: O(k3logn)

code:还是复制的

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define rpe(i,r,l) for(int i=r;i>=l;--i)
#define dyes cerr<<"yes"<<endl
#define rpp(i,x,e,head) for(int i=head[x];~i;i=e[i].next)
template <class Type> inline void read(Type &cur){
    Type ret=0,flag=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        ret=ret*10+ch-'0';
        ch=getchar();
    }
    cur=ret*flag;
}
const int mod=1e9+7;
typedef long long ll;
ll n,k;
struct matrix{
    ll s[20][20];
    matrix(){memset(s,0,sizeof(s));}
}A,I;
matrix operator * (const matrix &a,const matrix &b){
    matrix c;
    rep(i,0,14){
        rep(j,0,14){
            rep(k,0,14){
                c.s[i][j]=(c.s[i][j]+a.s[i][k]*b.s[k][j]%mod+mod)%mod;
            }
        }
    }
    return c;
}

matrix qpow(matrix a,ll x){
    matrix c=I;
    while(x){
        if(x&1)
            c=c*a;
        a=a*a;
        x>>=1;
    }
    return c;
}
int main(int argc,const char * argv[]){
    read(n);read(k);
    A.s[0][0]=1;
    rep(i,1,k){
        A.s[i][0]=A.s[i][i]=1;
        rep(j,0,i){
            A.s[i][j]=(A.s[i-1][j]+A.s[i-1][j-1])%mod;
        }
    }
    rep(i,0,14)
        I.s[i][i]=1;
    A.s[k+1][k]=1;A.s[k+1][k+1]=2;
    matrix ans;
    ans=qpow(A,n-1);
    ll fans=0;
    rep(i,0,k){
        fans=((fans+ans.s[k+1][i]+ans.s[k][i])%mod+mod)%mod;
    }
    cout<<fans<<endl;
    return 0;
}

T2
离线询问: x=0get(l1,r1,x)get(l2,r2,x)
get表示区间 [l,r] 中x的出现次数。
q,n105
我们把这个式子拆开,
维护: (l1,r2)[x],(l1,l21)[l],(r1+1,r2)[r],(r1+1,l21)[c]
分别代表区间内数字的个数。
那么 ans=(x2l2r2+c2)2

于是开始愉快的莫队吧!

拷贝代码:

//维护:(l1,r2)[z],(l1,l2-1)[l],(r1+1,r2)[r],(r1+1,l2-1)[c]
//ans=(x^2-l^2-r^2)/2+(c^2)/2; 
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define rpe(i,r,l) for(int i=r;i>=l;--i)
#define dyes cerr<<"yes"<<endl
#define rpp(i,x,e,head) for(int i=head[x];~i;i=e[i].next)
template <class Type> inline void read(Type &cur){
    Type ret=0,flag=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        ret=ret*10+ch-'0';
        ch=getchar();
    }
    cur=ret*flag;
}
typedef long long ll;
const int maxn=5e4+10;
inline ll read(){
    ll ret=0,flag=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        ret=(ret<<1)+(ret<<3)+ch-'0';
        ch=getchar();
    }
    return ret*flag;
}
ll belong[maxn];
struct node{
    int l,r;
    int id;int mul;
}e[maxn<<2];
inline bool cmp(const node &a,const node &b){
    if(belong[a.l]==belong[b.l])
        return a.r<b.r;
    return belong[a.l]<belong[b.l];
}
int cnt=0;
inline void add(ll l,ll r,ll mul,ll id){
    e[++cnt].l=l;e[cnt].r=r;
    e[cnt].id=id;e[cnt].mul=mul;
}
int n,m;
ll a[maxn];int num[maxn];
inline ll squre(ll x){return x*x;}
ll ans;
inline void upd(ll p,ll delta){
    ans-=squre(num[a[p]]);
    num[a[p]]+=delta;
    ans+=squre(num[a[p]]);
}
ll tans[maxn];
inline void modui(){
    ans=0;
    for(int i=1,l=1,r=0;i<=cnt;++i){
        for(;l<e[i].l;++l)
            upd(l,-1);
        for(;l>e[i].l;--l)
            upd(l-1,1);
        for(;r<e[i].r;++r)
            upd(r+1,1);
        for(;r>e[i].r;--r)
            upd(r,-1);
        tans[e[i].id]+=ans*(e[i].mul);
    }
}
int main(int argc,const char * argv[]){
    read(n);
    rep(i,1,n)
        read(a[i]);
    read(m);
    int size=sqrt(n);
    rep(i,1,n)
        belong[i]=(i-1)/size+1;
    int l1,l2,r1,r2;
    rep(i,1,m){
        read(l1);read(r1);read(l2);read(r2);
        add(l1,r2,1,i);
        add(l1,l2-1,-1,i);
        add(r1+1,r2,-1,i);
        add(r1+1,l2-1,1,i);
    }
    sort(e+1,e+cnt+1,cmp);
    modui();
    for(int i=1;i<=m;i++)
        cout<<tans[i]/2LL<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值