JZOJ 3960 鸡腿の出行

Posted rrsb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JZOJ 3960 鸡腿の出行相关的知识,希望对你有一定的参考价值。

SOL: 

  我们可以用tarjan求割点和边双,然后便成了一颗树,问题转成了 树上两点距离。

#include<bits/stdc++.h>
#define ull unsigned long long 
#define LL long long
#define mo 998244353
#define B 80
using namespace std;
//const int _P=1000007;
//const int _N=1000005;
//struct HashMap{
//  int head[_P],inum,clk;
//  int tag[_P];
//  ull h[_N]; int c[_N],g[_N],next[_N];
//  void _new(){
//    ++clk; inum=0;
//  }
//  int Head(int x){
//    return tag[x]!=clk?(tag[x]=clk,head[x]=0):head[x];
//  }
//  int &get(ull _h,int _c){
//    int hs=(_h*233+_c)%_P;
//    for (int p=Head(hs);p;p=next[p])
//      if (h[p]==_h && c[p]==_c)
//    return g[p];
//    h[++inum]=_h; c[inum]=_c; g[inum]=0; next[inum]=head[hs]; head[hs]=inum;
//    return g[inum];
//  }
//}f[2];
struct Ha{
    #define HaN 1000007
    #define HaM 1000007
    int head[HaN],net[HaM],fall[HaM],tag[HaN],tot,tim,
    c[HaM],g[HaM];
    ull h[HaM];
    void _new() {++tim; tot=0;}
    int push(int x) {
        return (tag[x]^tim)?(tag[x]=tim,head[x]=0):head[x];
    }
    int &get(ull _h,int _c) {
        static int hs;
        hs=(_h*233+_c)%HaN;
        for (int i=push(hs);i;i=net[i]) 
         if (h[i]==_h&&c[i]==_c) return g[i];
        h[++tot]=_h,c[tot]=_c; g[tot]=0; net[tot]=head[hs]; head[hs]=tot;
        return g[tot];
    }
}f[2];
int n,m,g,p,c,nc; char ha[107],pa[107];
LL K,ff[107][107],sum[107*107],l,r,ans;
ull se[107],h,tt,nh;
signed main () {
//    freopen("c.in","r",stdin);
    scanf("%d%d%lld",&n,&m,&K);
    scanf("%s",ha+1); scanf("%s",pa+1);
    ff[1][1]=K;
    for (int i=1;i<=n;i++)
     for (int j=1;j<=m;j++)
      ff[i+1][j]+=ff[i][j]>>1,ff[i][j+1]+=ff[i][j]>>1,ff[i][j]&=1;
    for (int i=1;i<=n;i++) ans+=(ha[i]==1)*ff[i][m+1],ff[i][m+1]=0;
    for (int i=1;i<=m;i++) ans+=(pa[i]==1)*ff[n+1][i],ff[n+1][i]=0;
    se[0]=1; for (int i=1;i<=m;i++) se[i]=se[i-1]*B;
    int t=0; f[t]._new();
    ull tmp=0; for (int i=m;i;i--) tmp=tmp*B+ff[1][i];
    f[t].get(tmp,0)=1;
    for (int i=1;i<=n*m;i++,t^=1){
    int x=(i-1)/m+1,y=(i-1)%m+1;
    f[t^1]._new();
    for (int p=1;p<=f[t].tot;p++){
      h=f[t].h[p]; c=f[t].c[p],g=f[t].g[p];
      tt=h%80;
      nh=h/80+se[m-1]*ff[x+1][y]; nc=c;
      if (y<m) nh+=(tt+1)/2;
      else nc+=((tt+1)/2)*(ha[x]==1);
      if (x<n) nh+=se[m-1]*(tt/2);
      else nc+=(tt/2)*(pa[y]==1);
//       cerr<<nh<<‘ ‘<<nc<<endl;
      (f[t^1].get(nh,nc)+=g)%=mo;
      nh=h/80+se[m-1]*ff[x+1][y]; nc=c;
      if (y<m) nh+=tt/2;
      else nc+=(tt/2)*(ha[x]==1);
      if (x<n) nh+=se[m-1]*((tt+1)/2);
      else nc+=((tt+1)/2)*(pa[y]==1);
//      cerr<<nh<<‘ ‘<<nc<<endl;
      (f[t^1].get(nh,nc)+=g)%=mo;
    }
  }
    for (int q=1;q<=f[t].tot;q++) (sum[f[t].c[q]]+=f[t].g[q])%=mo;
    for (int i=1;i<=n*m;i++) (sum[i]+=sum[i-1])%=mo;
    scanf("%d",&p);
    while (p--) {
      scanf("%lld%lld",&l,&r);
      l=max(l,ans); r=min(r,ans+n*m);
      if (l>r){printf("0
"); continue;}
      if (l==ans) printf("%d
",sum[r-ans]);
      else printf("%d
",(sum[r-ans]+mo-sum[l-ans-1])%mo);
    }
    return 0; 
}

 

以上是关于JZOJ 3960 鸡腿の出行的主要内容,如果未能解决你的问题,请参考以下文章

魔性の分块 | | jzoj1243 | | 线段树の暴力

P3960 列队

P3960 列队

luoguP3960 [noip2017]列队(树状数组)

luogu3960 列队

LG 3960 列队