zoukankan      html  css  js  c++  java
  • 【二维前缀和】

    https://nanti.jisuanke.com/t/31434

    直接搬题解:

    https://www.cnblogs.com/dilthey/p/9757781.html

    考虑普通的 dp[i][j]=a=L+1ib=D+1j((a==i&&b==j)?0:dp[a][b])dp[i][j]=∑a=L+1i∑b=D+1j((a==i&&b==j)?0:dp[a][b]),显然就是一整个大方块去掉一小格求和,

    其中,D=max(0,ik1)D=max(0,i−k−1) 为下开边界,L=max(0,jk1)L=max(0,j−k−1) 为左开边界,

    如果我们老老实实的纯暴力DP,显然就是 O(WHK2)O(WHK2) 的时间复杂度,能过有鬼……

    需要使用前缀和优化,不妨假设 sum[i][j]=a=1ib=1jdp[a][b]sum[i][j]=∑a=1i∑b=1jdp[a][b],

    那么,显然有状态转移方程 dp[i][j]=(sum[i1][j]+sum[i][j1]sum[i1][j1])(sum[D][j]+sum[i][L]sum[D][L])dp[i][j]=(sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1])−(sum[D][j]+sum[i][L]−sum[D][L]),

    进而显然有状态转移方程:

    sum[i][j]=(sum[i1][j]+sum[i][j1]sum[i1][j1])+dp[i][j]=2(sum[i1][j]+sum[i][j1]sum[i1][j1])(sum[D][j]+sum[i][L]sum[D][L])sum[i][j]=(sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1])+dp[i][j]=2(sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1])−(sum[D][j]+sum[i][L]−sum[D][L])

    最后,易知答案为 dp[h][w]=sum[h][w](sum[h1][j]+sum[i][w1]sum[h1][w1])dp[h][w]=sum[h][w]−(sum[h−1][j]+sum[i][w−1]−sum[h−1][w−1])。

    AC代码:

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

    const ll MOD=998244353;
    const int maxn=2000+10;

    int w,h,k;
    ll sum[maxn][maxn];

    int main()
    {
    scanf("%d%d%d",&w,&h,&k);

    memset(sum,0,sizeof(sum));
    sum[1][1]=1;
    for(int i=1;i<=h;i++)
    {
    for(int j=1;j<=w;j++)
    {
    if(i==1&&j==1) continue;
    int L=max(0,i-k-1),D=max(0,j-k-1);
    sum[i][j]=2*(sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1])-(sum[L][j]+sum[i][D]-sum[L][D]);
    while(sum[i][j]<0) sum[i][j]+=MOD; sum[i][j]%=MOD;
    }
    }
    ll ans=sum[h][w]-sum[h-1][w]-sum[h][w-1]+sum[h-1][w-1];
    while(ans<0) ans+=MOD; ans%=MOD;
    printf("%lld",ans);
    }

    zquoj 25001

    题意:图会给一个正方形,然后接下来给你一个边长的倾斜45度角的正方形,这个正方形能罩到的元素和最大为多少。

    直接旋转矩阵45度角然后直接前缀和求就行了

    #include<bits/stdc++.h>
    #define numm ch-48
    using namespace std;
    template <typename T>
    void read(T &res) {
    bool flag=false;char ch;
    while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
    for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
    flag&&(res=-res);
    }
    template <typename T>
    void write(T x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    }
    const int maxn=405;
    int a[maxn][maxn];
    int b[maxn*2][maxn*2];
    int main()
    {
    int n,m,k,x,y,xl,yl,xr,yr;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    scanf("%d",&a[i][j]);
    m=n*2-1;//新矩阵的大小
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    b[i+j-1][n-i+j]=a[i][j];//把矩阵旋转过来
    for(int i=1;i<=m;i++){
    for(int j=1;j<=m;j++){
    printf("%d ",b[i][j]);
    }
    printf("\n");
    }
    for(int i=1;i<=m;i++)
    for(int j=1;j<=m;j++)
    b[i][j]+=b[i][j-1];//前缀和
    for(int j=1;j<=m;j++)
    for(int i=1;i<=m;i++)
    b[j][i]+=b[j-1][i];//前缀和
    int ans=0;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
    x=i+j-1,y=n-i+j;//求旋转后的坐标
    xl=x-k,yl=y-k,xr=x+k,yr=y+k;//求左上角、右下角的坐标
    if(xl<1) xl=1;
    if(yl<1) yl=1;
    if(xr>m) xr=m;
    if(yr>m) yr=m;//超出矩阵外的部分要去掉
    ans=max(ans,b[xr][yr]-b[xr][yl-1]-b[xl-1][yr]+b[xl-1][yl-1]);//更新答案
    }
    printf("%d\n",ans);
    return 0;
    }

  • 相关阅读:
    TEN
    out.println()、document.write()、document.getelementbyid()
    正则表达式
    DOM与BOM
    伪类和伪元素
    Grid(未完全完成)
    position
    表单
    API,WEB API
    Event Flow
  • 原文地址:https://www.cnblogs.com/hgangang/p/11562800.html
Copyright © 2011-2022 走看看