UOJ Logo kczno1的博客

博客

论如何用dinic ac 最大流 加强版

2018-03-04 15:49:09 By kczno1

https://loj.ac/problem/127

这题就是数据很强的网络流模板题。。

导致正常的$dinic$及一些方法无法$ac$

目前有两个人用$push-relabel\ ac$,以及一个$dinic\ ac$(就是我)。

趁着没被再次$hack$发一发

首先有一个技巧,

$for(lim=2^k;lim;lim>>=1)$只跑$>=lim$的边

听说这样复杂度会优化成$O(nmlogC)$,我也不知道为什么

不过有的数据(包括随机数据)这样写会比原来还慢

而且后来被 @negiizhao $hack$了

我看到一个代码跑的很快但$wa$了极少的点

对拍后发现

Edge& forward = g[u][i], back = g[forward.dest][forward.back];

他没给反向边加流量!

我受到启发,先不加反向边跑一遍,然后一次性把反向边都加进去,然后再跑一遍。

事实证明这样效果很好。

因为大部分数据(包括随机数据)第一次就跑出了最优解,其余的也都跑出了较接近的解

(还顺便拿下了另一题的$rank1$)

$ac$代码:https://loj.ac/submission/69717

$upd$:原来那样被@oscar $hack$了,

于是我改进了一下,重复:不退流跑,一次性退流。

而且这样也比原来更简洁。

https://loj.ac/submission/71183

$upd:$已被@negiizhao卡成$O(n^{1.5}m)$

对于给定模数和w的字符串hash的hack

2018-02-01 20:24:40 By kczno1

其实就是我看到了http://uoj.ac/submission/151390 ,于是想把他$hack$了..

$hack$它实际上就是要找到一个$a$,使得$\sum_{i} a_{i}*w^{i}=0(mod D)$

($w$指的就是里面的那个$613613$那个东西,不知道叫什么;$D$就是指模数)

如果$w$跟字符集大小一样的话其实$hack$是很方便的,只要把$D$转化成$w$进制就行了.

不然的话我就只会暴力了..

把它转化成背包问题,然后用$bitset$优化

因为这人模数太大了,数组也开不下,所以要输出方案的话就得多用一个答案长度的时间.

需要跑几分钟.

($stl$的$bitset$在$n=2333333333$时会$re$,我猜是因为它是用$int$存储的,然后变成负数了)

(找到串使得会被误判成和$aaa..aa$相同后还得做些操作)

(话说重测后发生了一些神奇的事情..比如我从$23ms$变成了$8ms$,排行榜上的顺序也发生了一些变化)

[Ynoi2018]末日时在做什么?有没有空?可以来拯救吗?题解&&求证复杂度

2018-01-26 11:57:02 By kczno1

分块

块内需要维护前缀后缀全局的最大子段和

前缀后缀的求个凸包就行了

全局的话,每次求出当前最大子段和及长度,并求出使长度变化全局至少要加多少

因为加的是正数,所以一旦变化长度一定是变长的

所以只会变$n$次

求这个可以直接二分,但是是$\log{值域}$的

更好的方法是考虑以$i$为右端点时,就是要求$\min{(ans_{s}-(s_{i}-s_{j}))/((i-j)-ans_{len})}$,其中$j < i-ans_{len}$

所以可以从左到右枚举$i$,维护$(j,-s_{j})$的凸包,然后在凸包上二分.

时间$O(n \sqrt{n \log{n} })$

但是其实还有一个问题,就是当加在一个块的一个部分时,其答案长度可能变短

这样时间就没法证了..

我既不会证也不会卡,只能求出大佬了..

(其实我向$lxl$要了题解..但感觉太麻烦了而且常数大就写了这个)

(如果能有人优化下面代码或者自己写一个然后打败标算也是极好的)

(其实这个代码是很难过的,我在$luogu$上试了十几个分块长度才过的,不过一过就踩了标算.)


#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define pb push_back
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)
#define mid (l+r>>1)

template <typename T> inline void chmin(T &x,const T &y)
{
    if(x>y)x=y;
}
template <typename T> inline void chmax(T &x,const T &y)
{
    if(x<y)x=y;
}

const int ch_top=6e6;
char ch[ch_top],*now_r=ch-1;
char ch_w[ch_top],*now_w=ch_w-1;
#define gc (*++now_r)
#define c (*now_r)
int read()
{
    while(gc<'-');
    if(c=='-')
    {
        int x=gc-'0';
        while(gc>='0')x=x*10+c-'0';
        return -x;
    }
    int x=c-'0';
    while(gc>='0')x=x*10+c-'0';
    return x;
}
int readz()
{
    while(gc<'-');
    int x=c-'0';
    while(gc>='0')x=x*10+c-'0';
    return x;
}
#undef c
void write(ll &ans)
{
    if(ans<10){*++now_w='0'+ans;*++now_w='\n';return ;}
    static char st[20];
    int top=0;
    do{st[++top]='0'+ans%10;}while(ans/=10);
    do{*++now_w=st[top];}while(--top);
    *++now_w='\n';
}

#define B(x) ((x-1)/L)
const int N=1e5+5,L=/*4*/192,K=N/L+5;
const ll inf=1e11+2e9+1;
int n;
ll a[N];
struct TU
{
int q[L];ll s[L];
int head,tail;
};
struct BLOCK
{
int l,r;
ll ans;int anslen;ll nex;
ll ad;
TU pre,suf;ll sum;
bool full;
};
BLOCK block[K],*b,*e,*belong[N];

namespace BUILD
{
ll a[L];
ll ns[L];int nq[L];
ll ans;int anslen;
bool ok(const ll &x)
{
    ll s=0,li=ans+anslen*x;
    rep(i,0,L-1)
    {
        s=(s+a[i]+x<0)?0:s+a[i]+x;
        if(s>li)return 1;
    }

    return 0;
}
void build(BLOCK &k,bool init=1)
{
    ll x=k.ad,*_a=::a+k.l;
    k.ad=0;
    rep(i,0,L-1)a[i]=(_a[i]+=x);
    ll s;
   ans=0;anslen=0;
    s=0;int len=0;
    rep(i,0,L-1)
    {
        s+=a[i];
        if(s<0){s=0;len=0;}
        else
        {
            ++len;
            if(s>ans){ans=s;anslen=len;}
            else
            if(s==ans&&len>anslen)anslen=len;
        }
    }
    k.ans=ans;k.anslen=anslen;

    if(/*!ok(inf)*/anslen==L){k.nex=inf;k.pre.head=k.suf.head=k.pre.tail=k.suf.tail=0;k.pre.s[0]=k.suf.s[0]=k.sum=ans;k.full=1;return ;}
if(init)
{
    int /*head=0,*/tail=-1;
    ll *ns=k.pre.s;int *nq=k.pre.q;
    s=0;
    rep(i,1,L)
    {
        s+=a[i-1];
        while(tail>=0&&ns[tail]<=s)--tail;
        while(tail>=1&&(nq[tail-1]-i)*(ns[tail]-s)>=(nq[tail]-i)*(ns[tail-1]-s))--tail;
        ++tail;
        nq[tail]=i;ns[tail]=s;
    }
    k.pre.head=/*head*/0;k.pre.tail=tail;
    k.sum=s;

    /*head=0;*/tail=-1;
    ns=k.suf.s;nq=k.suf.q;
    s=0;
    rep(i,1,L)
    {
        s+=a[L-i];
        while(tail>=0&&ns[tail]<=s)--tail;
        while(tail>=1&&(nq[tail-1]-i)*(ns[tail]-s)>=(nq[tail]-i)*(ns[tail-1]-s))--tail;
        ++tail;
        nq[tail]=i;ns[tail]=s;
    }
    k.suf.head=/*head*/0;k.suf.tail=tail;
}
else
{
    ll *ns=k.pre.s;int *nq=k.pre.q;
    int i=k.pre.tail,head=k.pre.head;
    ns[i]+=x*nq[i];
    k.sum=ns[i];
    while(--i>=head)
    {
        ns[i]+=x*nq[i];
        if(ns[i]<=ns[i+1]){k.pre.head=i+1;break;}
    }


    ns=k.suf.s;nq=k.suf.q;
    i=k.suf.tail;head=k.suf.head;
    ns[i]+=x*nq[i];
    while(--i>=head)
    {
        ns[i]+=x*nq[i];
        if(ns[i]<=ns[i+1]){k.suf.head=i+1;break;}
    }
}
/*  ll l=0,r=10000;
    while(!ok(r)){r<<=1;if(r>=inf){r=inf;break;}}
    while(l+1!=r)
    if(ok(mid))r=mid;
    else l=mid;
    k.nex=r;*/
    ll nex=inf;
static bool may[L];
    s=0;
    per(i,L-1,anslen)
    {
        may[i]=s<=0;
        s=s+a[i]<0?0:s+a[i];
    }

    s=0;ll y=ans;
    int top=0;
    ns[0]=0;nq[0]=-1;
    int i=anslen,j=0;
    rep(k,0,i-1)y-=a[k];
    while(i<L)
    {
        s-=a[j];y-=a[i];

        if(may[i])
        {   
        //int x=i-anslen;
#define x j
        if(top<5)
        {
            rep(h,0,top)
            if((x-nq[h])*nex>y-ns[h])nex=(y-ns[h])/(x-nq[h]);
        }
        else
        {
            int l=0,r=top;
            while(l!=r)
            if((nq[mid+1]-x)*(ns[mid]-y)>=(nq[mid]-x)*(ns[mid+1]-y))l=mid+1;
            else r=mid;

            if((x-nq[l])*nex>y-ns[l])nex=(y-ns[l])/(x-nq[l]);
        }
#undef x
        }

        while(top>=1&&(nq[top-1]-j)*(ns[top]-s)>=(nq[top]-j)*(ns[top-1]-s))--top;
        if(s>ns[top]){ns[++top]=s;nq[top]=j;}
        ++i;++j;
    }

    k.nex=ok(nex)?nex:nex+1;
//  printf("%lld\n",k.nex);
}
};
using BUILD::build;

int main()
{
//  freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    ch[fread(ch,1,ch_top,stdin)]=0;
    n=readz();int m=readz();
    rep(i,1,n)a[i]=read();
    b=block;e=b-1;
    for(int l=1;l<=n;)
    {
        int r=l+L-1;
        if(l==1)r=l+L*2; 
        if(l+L*2>=n)r=n;
        ++e;
        e->l=l;e->r=r;
        while(l<=r){belong[l]=e;++l;}
    }
    for(BLOCK *p=b+1;p<e;++p)build(*p);
    while(m--)
    {
        while(gc<'0');
        if(*now_r=='1')
        {
            int l=readz(),r=readz(),x=readz();
            BLOCK *bl=belong[l],*br=belong[r];
            if(bl==br)
            {
                rep(i,l,r)a[i]+=x;
                if(bl>b&&bl<e)
                {
                    if(bl->full)bl->ans+=(ll)x*(r-l+1);
                    else build(*bl);
                }
            }
            else
            {
                int bl_r=bl->r;
                rep(i,l,bl_r)a[i]+=x;
                if(bl>b)
                {
                    if(bl->full)bl->ans+=(ll)x*(bl_r-l+1);
                    else build(*bl);
                }

                while(++bl<br)bl->ad+=x;

                int br_l=br->l;
                rep(i,br_l,r)a[i]+=x;
                if(br<e)
                {
                    if(br->full)br->ans+=(ll)x*(r-br_l+1);
                    else build(*br);
                }
            }
        }
        else
        {
            int l=readz(),r=readz();
        //  if(r-l<=L*2)
            if(belong[l]==belong[r])
            {   
                ll ans=0,s=0,x=belong[l]->ad;
                rep(i,l,r)
                {
                    s=(s+a[i]+x<0)?0:s+a[i]+x;
                    if(s>ans)ans=s;
                }
                write(ans);
                continue;
            }
            ll ans=0,s=0;
            BLOCK *bl=belong[l],*br=belong[r];
            int bl_r=bl->r;ll x=bl->ad;
            rep(i,l,bl_r)
            {
                s=(s+a[i]+x<0)?0:s+a[i]+x;
                if(s>ans)ans=s;
            }
            while(++bl<br)
            {
                x=bl->ad;
                if(bl->full)
                {
                    s+=bl->ans+x*L;
                    if(s>ans)ans=s;
                }
                else
                if(x>=bl->nex)
                {
                    build(*bl,0);
                    if(bl->ans>ans)ans=bl->ans;
                    if(s+bl->pre.s[bl->pre.head]>ans)ans=s+bl->pre.s[bl->pre.head];
                    s=max(0LL,max(s+bl->sum,bl->suf.s[bl->suf.head]));
                }
                else
                {
                    if(bl->ans+x*bl->anslen>ans)ans=bl->ans+x*bl->anslen;
                #define get q->s[q->head]+x*q->q[q->head]
                #define pop while(q->head<q->tail&&q->s[q->head]<q->s[q->head+1]+x*(q->q[q->head+1]-q->q[q->head]))++q->head;
                    TU *q=&bl->pre;
                    pop
                    if(s+get>ans)ans=s+get;
                    q=&bl->suf;
                    pop
                    s=max(0LL,max(s+bl->sum+x*L,get));
                #undef get
                #undef pop
                }
            }
            int br_l=br->l;x=br->ad;
            rep(i,br_l,r)
            {
                s=(s+a[i]+x<0)?0:s+a[i]+x;
                if(s>ans)ans=s;
            }
            write(ans);
        }
    }
    fwrite(ch_w,1,now_w-ch_w+1,stdout);
}

hackerrank Suffix Rotation

2017-12-25 18:04:14 By kczno1

https://www.hackerrank.com/contests/w28/challenges/suffix-rotation/problem

首先最后一定是能排成从小到大的,且每次一定是把最小的字符往前移。

而且无论如何移动前i个字符,第i+1之后的字符在环上的相对位置一定是不变的。

那么当第i个字符最后一位确定了之后,后面的字符串一定是固定的。

用$dp[j]$表示排完前$i(i=s[j])$个字符,最后一位为$j$的最小步数。

考虑从第$i-1$个字符到第$i$个字符的过程,每一块连续的$i$都是一起移动的,而且每次都是把一个块的开头移动到前面。

所以说$dp[j]$的意思更正为最后一块为$j$。(可以让每个块用开头代表)

考虑每个第$i-1$个字符的最后一块$k$的贡献,

定义$next[k]$为删去前$i-1$个字符后块$k$后面的第一个位置,$cnt[i]$为字符$i$的块的个数。

若$s[next[k]]!=i$,则对任意$j,dp[j]=dp[k]+cnt[i]$

若$s[next[k]]=i$,

设$next[k]$所属的块为$j'$

(1)若$next[k]$不是$j'$的块首,那么同上

(2)若$next[k]$是$j'$块首

对$j!=j'$,因为块$j'$不需要移动,所以$dp[j]=dp[k]+cnt[i]-1$

对$j'$,若$cnt[i]>1$,则其他$j$必须先移动,所以$j'$仍需要移动,所以$dp[j']=dp[k]+cnt[i]$;

          若$cnt[i]=1$,则$dp[j']=dp[k]$

记个最小值就$O(n)$了

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define pb push_back
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)

template <typename T> inline void chmin(T &x,const T &y)
{
    if(x>y)x=y;
}
template <typename T> inline void chmax(T &x,const T &y)
{
    if(x<y)x=y;
}

const int N=1e3+5,U=256;
int n;
char s[N];
int pre[N],nex[N];
int a[U][N];
int dp[N];

int main()
{
    freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    int tt;
    cin>>tt;
    while(tt--)
    {
        scanf("%s",s+1);
        int n=strlen(s+1);
        char mx=0;
        rep(i,1,n)chmax(mx,s[i]);

        rep(i,1,n) {nex[i]=i+1;pre[i]=i-1;}
        pre[1]=n;nex[n]=1;

        rep(i,0,mx)*a[i]=0;
        rep(i,1,n)a[s[i]][++*a[s[i]]]=i;
        rep(c,0,mx-1)
        {
            int top=0;
            rep(i,1,*a[c])
            {
                int x=a[c][i];
                if(s[pre[x]]==c) 
                {
                    nex[pre[x]]=nex[x];
                    pre[nex[x]]=pre[x];
                }
                else a[c][++top]=a[c][i];
            }
            *a[c]=top;
            rep(i,1,top) 
            {
                int x=a[c][i];
                nex[pre[x]]=nex[x];
                pre[nex[x]]=pre[x];
            }
        }

        int lastc=0;
        *a[0]=1;
        a[0][1]=0;
        nex[0]=1;
        dp[0]=0;
        rep(c,1,mx-1)
        if(*a[c])
        {
            int mn=N,cant=-1;
            rep(i,1,*a[lastc])
            {
                int k=a[lastc][i];
                int j=nex[k];
                if(s[j]==c&&s[pre[j]]!=c) 
                {
                    int now=dp[k]-1;
                    if(now<mn)
                    {
                        mn=now;
                        if(*a[c]==1) cant=-1;
                        else cant=j;
                    }
                    else 
                    if(now==mn)cant=-1;
                }
                else
                {
                    int now=dp[k];
                    if(now<mn){mn=now;cant=-1;}
                    else 
                    if(now==mn)cant=-1;
                }
            }
            mn+=*a[c];
            rep(i,1,*a[c])
            {
                int j=a[c][i];
                if(j!=cant)dp[j]=mn;
                else dp[j]=mn+1;
            }
            lastc=c;
        }

        int ans=N;
        rep(i,1,*a[lastc])chmin(ans,dp[a[lastc][i]]);
        printf("%d\n",ans);
    }
}

51nod 1303 交叉矩阵

2017-12-24 16:14:46 By kczno1

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1303

所求=总矩阵对数-相离矩阵对数-相包含矩阵对数

总矩阵对数=${矩阵数 \choose 2}$

考虑如何求有多少个全1矩阵。

先枚举右下角的端点$(i,j)$,维护以$(i,j)$为右下角的全1矩阵个数

枚举行$i$,从左到右枚举列$j$

用单调栈维护$k=1..j$到$j$的$up$的$min$ ($up[i][j]$表示点$(i,j)$向上有连续多少个1)

以$(i,j)$为右下角的矩阵个数=$min_k$的和,可以维护。

考虑如何求相包含矩阵对数。

枚举较大的矩阵($n*m$),则较小矩阵有${n+1 \choose 2} * {m+1 \choose 2}$个

所以用类似上面的方法,维护$1*f(m),n*f(m),n^2*f(m)$的和即可。($f(m)为{m+1 \choose 2} 的前缀和$)

考虑如何求相离矩阵对数。

即左右相离+上下相离-左上右下相离-右上左下相离

求出每个点作为四个方向的端点的矩阵个数,之后就轻松解决了。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define pb push_back
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)

const int N=1e3+5,D=1e9+7;
ll mi(ll x,int y=D-2)
{
    ll ans=1;
    while(y)
    {
        if(y&1)ans=ans*x%D;
        x=x*x%D;y>>=1;
    }
    return ans;
}
int n,m;
char b[N][N];
int up[N][N],down[N][N];
ll S1[N],S2[N],f[N],f2[N];
//S1[n]=sigma i; S2[n]=sigma i^2; f[n]=sigma S[i]
ll a[N],h[N];
ll cnt[N][N],cnt1[N][N],cnt2[N][N],cnt3[N][N];
//cnt 右下角 ;cnt1 左下角 ;cnt2 右上角 ;cnt3 左上角 
ll c[N],c1[N];

int main()
{
    freopen("1.in","r",stdin);//freopen("2.out","w",stdout);
    cin>>n>>m;
    rep(i,1,n)scanf("%s",b[i]+1);

    int mn=max(n,m);
    rep(i,1,mn){S1[i]=S1[i-1]+i;f[i]=f[i-1]+S1[i];}
    rep(i,1,mn){S2[i]=S2[i-1]+i*i;(f2[i]=f2[i-1]+S2[i])%D;}

    rep(i,1,n)
    rep(j,1,m) 
    if(b[i][j]=='1')up[i][j]=up[i-1][j]+1;
    per(i,n,1)
    rep(j,1,m) 
    if(b[i][j]=='1')down[i][j]=down[i+1][j]+1;

    ll ans=0;
    //+C2(tot_cnt) 
    //-相包含
    //-横相离-纵相离+左上右下相离+右上左下相离

    //-相包含 
    rep(i,1,n)
    {
        int top=0,ncnt=0;
        //ncnt sigma h_k
        ll s0=0,s1=0,s2=0;
        //s0=sigma f[h_k]
        //s1=sigma (j-k+1)*f[h_k]
        //s2=sigma (j-k+1)^2*f[h_k]
        rep(j,1,m)
        {
            (s2+=2*s1+s0)%=D;
            (s1+=s0)%=D;
            while(h[top]>up[i][j])
            {
                ncnt-=h[top]*(a[top]-a[top-1]);
                (s0-=f[h[top]]*(a[top]-a[top-1]))%=D;
                (s1-=f[h[top]]*(S1[j-a[top-1]]-S1[j-a[top]]))%=D;
                (s2-=f[h[top]]*(S2[j-a[top-1]]-S2[j-a[top]]))%=D;
                --top;
            }
            h[++top]=up[i][j];
            a[top]=j;
            ncnt+=h[top]*(a[top]-a[top-1]);
            (s0+=f[h[top]]*(a[top]-a[top-1]))%=D;
            (s1+=f[h[top]]*(S1[j-a[top-1]]-S1[j-a[top]]))%=D;
            (s2+=f[h[top]]*(S2[j-a[top-1]]-S2[j-a[top]]))%=D;

            cnt[i][j]=ncnt;
            (ans+=s2+s1)%=D;
        }
    }
    (ans*=mi(2))%=D;
    ans=-ans;

        //get cnt2
    rep(i,1,n)
    {
        int top=0,ncnt=0;
        rep(j,1,m) 
        {
            while(h[top]>down[i][j])
            {
                ncnt-=h[top]*(a[top]-a[top-1]);
                --top;
            }
            h[++top]=down[i][j];
            a[top]=j;
            ncnt+=h[top]*(a[top]-a[top-1]);
            cnt2[i][j]=ncnt;
        }
    }

    a[0]=m+1;
    //get cnt1
    rep(i,1,n)
    {
        int top=0,ncnt=0;
        per(j,m,1) 
        {
            while(h[top]>up[i][j])
            {
                ncnt-=h[top]*(a[top-1]-a[top]);
                --top;
            }
            h[++top]=up[i][j];
            a[top]=j;
            ncnt+=h[top]*(a[top-1]-a[top]);
            cnt1[i][j]=ncnt;
        }
    }
    //get cnt3
    rep(i,1,n)
    {
        int top=0,ncnt=0;
        per(j,m,1)
        {
            while(h[top]>down[i][j])
            {
                ncnt-=h[top]*(a[top-1]-a[top]);
                --top;
            }
            h[++top]=down[i][j];
            a[top]=j;
            ncnt+=h[top]*(a[top-1]-a[top]);
            cnt3[i][j]=ncnt;
        }
    }

    //-横相离 
    rep(i,1,n)
    rep(j,1,m) c[j]+=cnt[i][j];
    rep(i,1,n)
    rep(j,1,m) c1[j]+=cnt1[i][j];
    ll sum=0;
    rep(i,1,m)sum+=c[i];
    sum%=D;
//-----  +C2(tot_cnt) 
    (ans+=(sum+1)*sum/2)%=D;
//-----    
    per(i,m,1)
    {
        (sum-=c[i])%=D;
        (ans-=sum*c1[i])%=D;
    }

    //-纵相离 
memset(c,0,sizeof(c));memset(c1,0,sizeof(c1));
    rep(i,1,n)
    rep(j,1,m) c[i]+=cnt[i][j];
    rep(i,1,n)
    rep(j,1,m) c1[i]+=cnt2[i][j];
    sum=0;
    rep(i,1,n)sum+=c[i];
    sum%=D;
    per(i,n,1)
    {
        (sum-=c[i])%=D;
        (ans-=sum*c1[i])%=D;
    }

    //+左上右下相离
    rep(i,1,n)
    rep(j,1,m)cnt[i][j]+=cnt[i][j-1];
    rep(i,1,n)
    rep(j,1,m)(cnt[i][j]+=cnt[i-1][j])%=D;
    rep(i,1,n)
    rep(j,1,m)(ans+=cnt3[i][j]*cnt[i-1][j-1])%=D;

    //+左下右上相离 
    rep(i,1,n)
    per(j,m,1)cnt1[i][j]+=cnt1[i][j+1];
    rep(i,1,n)
    rep(j,1,m)(cnt1[i][j]+=cnt1[i-1][j])%=D;
    rep(i,1,n)
    rep(j,1,m)(ans+=cnt2[i][j]*cnt1[i-1][j+1])%=D;

    cout<<(ans%D+D)%D;
}

求助

2017-12-20 14:19:49 By kczno1

我想知道怎么求$[1,10^{11}]$内的质数个数

在网上找到如下代码,但不知道什么意思,希望有会的人能告诉我

#include <bits/stdc++.h>  
#define ll long long  
using namespace std;  
ll f[340000],g[340000],n;  
void init(){  
    ll i,j,m;  
    for(m=1;m*m<=n;++m)f[m]=n/m-1;  
    for(i=1;i<=m;++i)g[i]=i-1;  
    for(i=2;i<=m;++i){  
        if(g[i]==g[i-1])continue;  
        for(j=1;j<=min(m-1,n/i/i);++j){  
            if(i*j<m)f[j]-=f[i*j]-g[i-1];  
            else f[j]-=g[n/i/j]-g[i-1];  
        }  
        for(j=m;j>=i*i;--j)g[j]-=g[j/i]-g[i-1];  
    }  
}  
int main(){  
    cin>>n;
        init();  
        cout<<f[1]<<endl;  
    return 0;  
}

求hack

2017-12-13 14:44:08 By kczno1

http://uoj.ac/problem/219

为什么这题单取模哈希也没被$hack$啊。。

求教如何$hack$

( 而且$O(nlog^2n)$还拿了$rank1$ )

bzoj3508

2017-11-29 14:29:06 By kczno1

定义数组$a:$$a[i]=1$表示最终第$i$个灯泡亮,$0$表示暗。

则操作相当于对$a$区间异或。

差分,即令$b[i]=a[i]$ $xor$ $a[i-1]$

则$a$的区间$[l,r]$异或等价于$b[l],b[r+1]$异或。

把所有$b[i]=1$的$i$拿出来,记作数组$q$

就是每次解决掉一对$q[i],q[j]$,代价为$g[q[j]-q[i]]$

( $g$可以$O(nl)$ $bfs$得到 )

状压$dp$,$O(2^{len}*len)$ ($len$为$q$的长度,$<=2*k$)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define pb push_back
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)

template <typename T> inline void chmin(T &x,const T &y)
{
    if(x>y)x=y;
}
template <typename T> inline void chmax(T &x,const T &y)
{
    if(x<y)x=y;
}

#define gc (c=getchar())
int read()
{
    char c;
    while(gc<'-');
    if(c=='-')
    {
        int x=gc-'0';
        while(gc>='0')x=x*10+c-'0';
        return -x;
    }
    int x=c-'0';
    while(gc>='0')x=x*10+c-'0';
    return x;
}

const int N=1e4+5,L=100+5,K=10,inf=N*N;
int n,k,l;
int a[N],b[N],g[N];
int top,q[K*2];
int dp[1<<K*2];

namespace GET_G
{
int q[N];
int a[L];
void get()
{
    rep(i,1,l)a[i]=read();
    rep(i,1,n) g[i]=N;
    g[0]=0;
    int tail=1;
    q[1]=0;
    rep(head,1,tail)
    {
        int x=q[head];
        rep(i,1,l)
        {
            int y=x+a[i];
            if(y<=n&&g[y]==N) g[q[++tail]=y]=g[x]+1;
            y=x-a[i];
            if(y>0&&g[y]==N) g[q[++tail]=y]=g[x]+1;
        }
    }
}
};

int DP(int u)
{
    if(dp[u]!=-1)return dp[u];
    dp[u]=inf;
    int i=0;
    while(!(u&(1<<i))) ++i;
    rep(j,i+1,top-1)
    if(g[q[j]-q[i]]!=N)
    if(u&(1<<j)) chmin(dp[u],DP(u-(1<<i)-(1<<j))+g[q[j]-q[i]]);
    return dp[u];
}

int main()
{
    freopen("1.in","r",stdin);//freopen("1.out","w",stdout);
    int tt;
    cin>>tt;
    while(tt--)
    {
        cin>>n>>k>>l;

        memset(a,0,sizeof(a));
        rep(i,1,k)a[read()]=1;
        top=0;
        rep(i,1,n+1)
        if(a[i]^a[i-1])q[top++]=i;

        GET_G::get();

        int u=(1<<top)-1;
        memset(dp+1,-1,u*sizeof(int));
        dp[0]=0;
        DP(u);
        if(dp[u]==inf) puts("-1");
        else printf("%d\n",dp[u]);
    }
}

一道挺妙的矩乘优化递推的题

2017-11-06 21:27:45 By kczno1

题意:

$f_{n}=\sum_{i=1}^{20} w_i*f_{n-i}$ (模一个常数)

给定$w_{1..20}$ , $f_{1..20}$ , 询问$f_n$

其中$n$以$k$进制给出,$k<=10$,$n$的位数$l<=1000$

$T$组询问,$k$都一样($T<=200$)

题解:

朴素想法是将$n$转化成$2$进制($O(l^2)$),快速幂优化矩乘($ O(l * \log_{2}{10} * 20^3 ) $)

然而这两个操作复杂度都过高,会$TLE$

考虑直接使用$k$进制,

$dp$求出所有$M^{j*k^i} ( j\in[0,k) )$

但这样$dp$复杂度为$O(l * 10 * 20^3 )$

但注意到只用$dp$一遍而不是$T$遍,所以是可以接受的。

这样单次询问复杂度就变成$ O(l * 20^3 ) $

注意到,我们要算的其实是一个$1*20$的矩阵乘多个$20*20$的矩阵

其实不用先把$20*20$的都乘起来再乘$1*20$的

可以直接依次乘

这样就只用$1*20$的乘$20*20$的

复杂度变成$ O(l * 20^2 ) $

可以通过。

srm 691 div1 - 500的各种做法

2017-10-17 19:34:30 By kczno1

题意:

$n$场比赛

打第i场加 $a_{i}$ 经验,且打完获得当前经验 * $b_{i}$ 的奖金

打完$n/2$场获得$x$的经验(保证$n$为偶数)

任意安排顺序,求最大奖金

$b_i<=10,n<=50,x和a_i<=10^5$

题解:

1 dp(标算)

如果不考虑$x$的话是可以贪心的。

因为考虑相邻两个$a_1,b_1,a_2,b_2$

交换后的变化=$a_2*b_1-a_1*b_2$

所以交换更优<=>$a_2/b_2>a_1/b_2$

只有$a/b$降序时无法交换,达到最优

所以$1..n/2$场与$n/2+1..n$场都是按$a/b$降序的。

按$a/b$降序排序后

枚举$n/2+1..n$场的$b_i$的和

然后dp,记录打了前几场,有几场在后面一半打,以及后面一半打的$b_i$的和。

复杂度$O(n^4*b^2)$ ,常数较小

2 随机化

先按$a/b$降序排序

然后考虑随机哪些点在后面一半打之后就可以贪心了

先让在后面一半的在后面一半打作为初始解

每次随机交换一个在前面的和在后面的

退火,甚至只有更优才交换,都能过。。

可以极快ac。

我目前也不知道怎么卡。。。

3 贪心+枚举

注意到$b$很小,而$b$一样的必定要让$a$大的在前面

(其实一开始想的是利用这一点暴力dp,但发现状态数会达到6^10,时空都炸)

利用这一点,暴力枚举每个$b$在后面$n/2$个占几个 然后在$O(n)$检验

最差情况下就是每个$b$都有$5$的$a$,差不多要枚举$10^7$次

勉强能过吧

共 51 篇博客