A题:给你一个n*m的矩阵,问里面有多少个只含w的子矩阵
解析:第一眼,暴力的方法3方,肯定会tle的。
这么想,枚举这个子矩阵的右下角,然后ans求和就行了。
枚举每一行,维护一个递增的单调栈,并且用一个res来记录当前能增加的,以当前枚举位置为右下角的矩阵的个数。
具体见代码
//
// Created by Matrix on 2015-10-04
// Copyright (c) 2015 Matrix. All rights reserved.
//
//
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
#define MAXN 9999
#define MAXSIZE 10
#define DLEN 4
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 2e3 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
inline int read() {
char c = getchar();
int f = 1;
while(!isdigit(c)) {
if(c == '-') f = -1;
c = getchar();
}
int x = 0;
while(isdigit(c)) {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int n, m;
char mp[maxn][maxn];
int h[maxn][maxn];
typedef pair <ll, ll> sta;
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("out.txt","w",stdout);
#endif
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = 1; i <= n; i++)
scanf("%s", mp[i] + 1);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(mp[i][j] == 'w') {
h[i][j] = h[i-1][j] + 1;
}
else h[i][j] = 0;
}
}
ll ans = 0;
stack <sta> s;
for(int i = 1; i <= n; i++) {
ll res = 0;
while(!s.empty()) s.pop();
for(int j = 1; j <= m; j++) {
sta u;
u.first = h[i][j];
u.second = 1;
if(!u.first) {
while(!s.empty()) s.pop();
res = 0;
continue;
}
while(!s.empty() && s.top().first > u.first) {
res -= s.top().first * s.top().second;
u.second += s.top().second;
s.pop();
}
res += u.first * u.second;
ans += res;
s.push(u);
}
}
printf("%I64d\n", ans);
}
return 0;
}
B题:给出a b,在10^15次方范围,问a,b之间的数字的流行度之和
解析:因为数字是a * a * b 并且b大于等于a,那么对于每一个数,我们要确定他的流行度,就枚举a,看是否能找到一个b,找得到,这就是一种情况,所有情况个数就是这个数的流行度。
这样太慢了,要求a,b之间,我们可以求1-b之间,再减去1-a-1之间的数的流行度之和。
那么,枚举i从1到tmp^(1/3),tmp除之,就得到tmp里面有多少个数是i*i的倍数,减去下限(i-1)就是1-tmp的答案。
具体见代码
//
// Created by Matrix on 2015-10-04
// Copyright (c) 2015 Matrix. All rights reserved.
//
//
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
#define MAXN 9999
#define MAXSIZE 10
#define DLEN 4
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
inline int read() {
char c = getchar();
int f = 1;
while(!isdigit(c)) {
if(c == '-') f = -1;
c = getchar();
}
int x = 0;
while(isdigit(c)) {
x = x * 10 + c -