省选武汉联测 1

数据好水。考试的时候感觉很摆,全程口胡,根本没写代码。

递归函数

场上看着这个东西寻思着一堆跳着的组合数求和怎么搞啊,推了半天单位根反演,未果,寻病终。

不是很知道他在干什么,贺了份代码。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
int mod=998444353;
int n,m,b,ans1,ans;
struct node{
    int a[20][20];
    node(){memset(a,0,sizeof(a));}
    node operator*(node s){
        node ret;
        for(int i=0;i<=m;i++)for(int j=0;j<=m;j++)for(int k=0;k<=m;k++)ret.a[i][j]=(ret.a[i][j]+1ll*a[i][k]*s.a[k][j])%mod;
        return ret;
    }
}A,B,C;
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=1ll*ans*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return ans;
}
node qpow(node a,int b){
    node ans;
    for(int i=0;i<=m;i++)ans.a[i][i]=1;
    while(b){
        if(b&1)ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}
int getans(int d,int r){
    if(m==1)return 1;
    int cnt=(n-r-2+d)/d;
    return (C*qpow(A,m+r-2)*qpow(B*qpow(A,d-1),cnt)).a[0][m];
}
signed main(){
    scanf("%d%d%d",&n,&m,&b);
    C.a[0][0]=1;
    for(int i=0;i<m;i++)B.a[i][i]=B.a[i][i+1]=1;
    B.a[m][m]=1;
    A=B;A.a[m-1][m]=0;B.a[m-2][m]=1;
    if(b==6)b=3;
    if(b==10)b=5;
    if(b==2||b==3||b==5||b==7){
        for(int d=b;d<=n;d*=b)ans=(ans+getans(d,n%d))%mod;
    }
    if(b==4||b==8||b==9){
        int t1,t2;
        if(b==9)t1=3;
        else t1=2;
        if(b==8)t2=3;
        else t2=2;
        for(int d=t1;d<=n;d*=t1)ans=(ans+getans(d,n%d))%mod;
        mod=t2;
        for(int d=t1;d<=n;d*=t1)ans1=(ans1+getans(d,n%d))%mod;
        mod=998444353;
        ans=1ll*(ans-ans1+mod)%mod*qpow(t2,mod-2)%mod;
    }
    printf("%d\n",ans);
    return 0;
}

火力规划

比较智慧。CF575I。

四个情况是对称的,只讨论第一种。

首先时间,\(x\)\(y\)\(x+y\) 是个四维偏序。三只 \(\log\) 看起来就很过不去。然而好像有人卡过去了。

考虑一下这四维有没有什么关系。发现我们要满足 \(x'\ge x,y'\ge y,x'+y'\le x+y+r\)。那么对 \(x'\ge x,y'\ge y\) 容斥,枚举强制不满足几个条件,就是两个三维偏序,还有一个 \(x'<x,y'<y,x'+y'\le x+y+r\)。容易发现第三个条件没用,所以还是三维偏序。

四个都做一遍就行了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n,q,ans[100010],x[100010],y[100010],d[100010],r[100010];
struct BIT{
    int n,m,c[10010][5010];
    #define lowbit(x) (x&-x)
    void update(int x,int y,int val){
        for(int i=x;i<=n;i+=lowbit(i)){
            for(int j=y;j<=m;j+=lowbit(j)){
                c[i][j]+=val;
            }
        }
    }
    int query(int x,int y){
        int sum=0;
        for(int i=x;i;i-=lowbit(i)){
            for(int j=y;j;j-=lowbit(j))sum+=c[i][j];
        }
        return sum;
    }
    void clear(){memset(c,0,sizeof(c));}
}c;
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=q;i++){
        int od;scanf("%d",&od);
        if(od==1)scanf("%d%d%d%d",&d[i],&x[i],&y[i],&r[i]);
        else scanf("%d%d",&x[i],&y[i]);
    }
    c.n=c.m=n;
    for(int i=1;i<=q;i++){
        if(d[i]==1)c.update(x[i],y[i],1),c.update(x[i],y[i]+r[i]+1,-1);
        if(d[i]==2)c.update(x[i],y[i]-r[i],1),c.update(x[i],y[i]+1,-1);
        if(d[i]==3)c.update(x[i]+1,y[i]+r[i]+1,1),c.update(x[i]+1,y[i],-1);
        if(d[i]==4)c.update(x[i]+1,y[i]+1,1),c.update(x[i]+1,y[i]-r[i],-1);
        if(!d[i])ans[i]+=c.query(x[i],y[i]);
    }
    c.clear();
    c.n=2*n;
    for(int i=1;i<=q;i++){
        if(d[i]==2)c.update(x[i]-y[i]+r[i]+n+2,y[i]+1,1),c.update(x[i]-y[i]+r[i]+n+2,y[i]-r[i],-1);
        if(d[i]==3)c.update(x[i]-y[i]-r[i]+n+1,y[i],1),c.update(x[i]-y[i]-r[i]+n+1,y[i]+r[i]+1,-1);
        if(!d[i])ans[i]+=c.query(x[i]-y[i]+n+1,y[i]);
    }
    c.clear();
    for(int i=1;i<=q;i++){
        if(d[i]==1)c.update(x[i]+y[i]+r[i]+1,n-y[i]+2,1),c.update(x[i]+y[i]+r[i]+1,n-y[i]-r[i]+1,-1);
        if(d[i]==4)c.update(x[i]+y[i]-r[i],n-y[i]+1,1),c.update(x[i]+y[i]-r[i],n-y[i]+r[i]+2,-1);
        if(!d[i])ans[i]+=c.query(x[i]+y[i],n-y[i]+1);
    }
    for(int i=1;i<=q;i++)if(!d[i])printf("%d\n",ans[i]);
    return 0;
}

再生核希尔伯特空间

根号分治。

建 AC 自动机,然后对询问串长根号分治。如果大于根号,那正常扫整个 fail 树统计答案。小于根号的,每次可以暴力统计每个节点的贡献。这部分如果用主席树多个 \(\log\),然而实际上可以直接分块统计链和,不带 \(\log\)

没写。

posted @ 2023-03-07 20:12  gtm1514  阅读(22)  评论(0编辑  收藏  举报