hammer

这个问题可以通过适当的分类来解决。

一般来说,当一个问题需要分类讨论时,尽量减少分支是很重要的。

例如,在这个问题中,我们可以假设墙的坐标总是正的,从而减少分支。

如果需要的话,我们可以通过乘以1-1来假设墙的坐标YY是正的,并且我们可以用以下条件分支来解决这个问题:

  • 如果X<YX<Y,他可以直接前往目标。
  • 如果X>YX>Y,他需要拿起锤子才能到达目标。
    • 如果Z>YZ>Y,他不能拿起锤子。
    • 如果Z<YZ<Y,他首先去ZZ拿起锤子,然后前往目标XX

calculation

考虑将 A 和 B 这两个数分别拆分出他的每一位存储在两个数组中,(拆分可以参考使用while循环,模10,除10等操作)然后可以从低位到高位模拟坚式加法计算,用标记变量记录有无进位和第几位进位即可。注意数据范围,需要开long long 。

pizza

考虑这个pizza是一个圆,我们知道这个圆的度数为360度,将旋转pizza转换为旋转着切,这也是显然的。我们可用一个数组to[360]来记录pizza的哪一度上挨过刀(被切过),然后统计这360个位置被切的相邻之间的最大值就是答案。这实际上类似于桶数组记录信息的方法。将给定的序列做个前缀和,然后依次模360的结果记录to数组就可以愉快的解决此问题了。

matrix

考虑将原始矩阵的上下左右对角线等八个方向都补充上原始矩阵的备份,然后依次枚举原始矩阵的每一个位置,从该位置的八个方向走N—1步组成一个数,由于N10N \le10,所以可以直接定义一个long long 变量存储。然后找最大值即可。

count

针对区间问题的一种典型方法是计算前缀和。

定义前缀和Si=j=1iAjS_i = \sum_{j=1}^{i}A_j,其中0iN0\leq i \leq N,问题可以解释如下:

满足以下条件的整数对(l,r)(l,r)有多少个?

  • 1lrN1\leq l\leq r\leq N
  • SrSl1=KS_r - S_{l-1}=K

这导致了一个临时的O(N2)O(N^2)解法:

ans = 0
for r in 1 .. n
    for l in 1 .. r
        if S[l-1] == S[r] - K
            ans += 1
output(ans)

如何消除第3行到第5行的循环以降低复杂度?

我们想要快速获得的是满足1lr1\leq l\leq rS[l1]=S[r]KS[l-1] = S[r]-Kll的数量。这可以通过一个关联数组来实现,例如在C++中使用std::map

因此,整个问题可以在O(NlogN)O(N \log N)的时间内解决。 用类似下面的代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,l,r) for(ll i=l;i<=r;i++)

signed main(){
    ll n,k;cin>>n>>k;
    vector<ll>a(n);rep(i,0,n-1)cin>>a[i];
    vector<ll>s(n+1);rep(i,0,n-1)s[i+1]=s[i]+a[i];
    map<ll,ll>mp;
    ll ans=0;
    rep(r,1,n){
        mp[s[r-1]]++;
        ans += mp[s[r]-k];
    }
    cout<<ans<<endl;
    return 0;
}

当然此题也有其他的解决方案,大家可以补充哈。