力扣寒假刷题笔记(20)2.17

一、每日一题

马走日象走田的移动方式,个人写法是DFS+记忆化,感觉一下子就能想到DFS,试了一下单纯DFS会超时,加一个备忘录就可以过了。

一开始没看懂概率是啥意思,以为是满足要求的走法除所有走法。后来想明白了,这里概率指的是选择某一种走法然后在棋盘上的概率。

int dix[]={-2,-2,-1,-1,1,1,2,2},diy[]={-1,1,-2,2,-2,2,-1,1};
double dp[101][25][25];
class Solution {
public:
    double sum=0,cnt=0;
    double dfs(int x,int y,int t,int n)
    {
        if(x<0||x>=n||y<0||y>=n) return 0;
        if(t==0) return 1.0;
        double res =0;
        if(dp[t][x][y]!=0) res+=dp[t][x][y];
        else {
            for(int i=0;i<8;i++)
            {
                int r = x+dix[i],c=y+diy[i];
                res+=dfs(r,c,t-1,n);
            }
            dp[t][x][y] = res;
        }
        return res/8;
    }
    double knightProbability(int n, int k, int row, int column) {
        memset(dp,0,sizeof dp);
        return dfs(row,column,k,n);
    }
};

二、前缀和

 

#include <iostream>
#include <algorithm>
using namespace std;
const int N=5010;
int r,n;
int m[N][N];
int main()
{
    cin>>n>>r;
    r = min(r,5001);
    for(int i=0;i<n;i++)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        m[++x][++y] += w;
    }
    for(int i=1;i<=5001;i++)
    {
        for(int j=1;j<=5001;j++)
        {
            m[i][j] += (m[i-1][j] + m[i][j-1] -m[i-1][j-1]);
        }
    }
    int val=0;
    for(int i=r;i<=5001;i++)
    {
        for(int j=r;j<=5001;j++)
        {
            val=max(val,m[i][j] - m[i-r][j]-m[i][j-r]+m[i-r][j-r]);
        }
    }
    cout <<val;
}

如果单纯地求前缀和然后再遍历每一个起始点会超时。

求区间[l,r]的和是k的倍数的个数。求区间和,我们可以通过前缀和来求出。我们规定sum[i]表示第1个元素到第i个元素的和。那么sum[r] - sum[l-1]就是区间[l,r]的和。区间[l,r]的和是k的倍数即(sum[r] - sum[l-1])%k == 0 即sum[r]%k == sum[l-1]%k。 

 也就是相同sum[i]的组合数再加上sum[0]即可。

#include <iostream>
using namespace std;
const int N=100010;
int m[N],s[N],res[N];
int n,k;
int main()
{
    cin>>n>>k;
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&m[i]);
        s[i] = (s[i-1] + m[i])%k;
        ans+=res[s[i]]; 
        res[s[i]]++;
    }
    cout<<ans+res[0];
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值