一、每日一题
马走日象走田的移动方式,个人写法是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];
}