下面不再说明题意了请自行读题,直接放contest链接。
https://vjudge.net/contest/151607
A.考虑当火车隔k站一停时
区间长度 >= k 的纪念品一定能买到
区间长度 <k 的纪念品最多覆盖一个停靠的站点
求出 n / k 个点, 每个点上覆盖的纪念品数累加即可
k 从 1 到 m 都需要求
我们只要把纪念品按区间长度排序
然后向后扫就可以了
总复杂度 O(nlog^2n)
1 #include <cstdio> 2 #include <algorithm> 3 4 #define lowbit(x) (x&(-x)) 5 6 using std::sort; 7 8 const int maxn = 300010; 9 10 int n, m, c[maxn]; 11 12 struct node { 13 int l, r, len; 14 bool operator < (const node &a) const { 15 return len < a.len; 16 } 17 }a[maxn]; 18 19 void add(int i, int x) { 20 while(i <= m) c[i] += x, i += lowbit(i); 21 } 22 23 int ask(int i) { 24 int ret = 0; 25 while(i > 0) ret += c[i], i -= lowbit(i); 26 return ret; 27 } 28 29 int main() { 30 scanf("%d %d", &n, &m); 31 for(int i = 1;i <= n;i ++) { 32 scanf("%d %d", &a[i].l, &a[i].r); 33 a[i].r ++, a[i].len = a[i].r - a[i].l; 34 } 35 sort(a + 1, a + n + 1); 36 for(int i = 1, j = 1, ans;i <= m;i ++) { 37 while(j <= n && a[j].len < i) { 38 add(a[j].l, 1); 39 add(a[j].r, -1); 40 j ++; 41 } 42 ans = n - j + 1; 43 for(int k = i;k <= m;k += i) 44 ans += ask(k); 45 printf("%d\n", ans); 46 } 47 }
B.一个暴力理论向上约等于O(n^3)的做法:
我们把原矩阵旋转45度,再扔掉那些对当前点贡献为0的点
就能得到一个对当前点有贡献的正方形点阵
从外到里,贡献系数递增
所以我们的做法就是枚举点,然后O(k)计算它的 f 函数值...
下面代码把 scanf 改成快读卡常数就能过了...
1 #include <cstdio> 2 3 #define rep(i, j, k) for(int i = j;i <= k;i ++) 4 5 long long s[2100][2100], ans = -1, tmp; 6 7 int n, m, k, t, p, q, ax, ay; 8 9 int main() { 10 scanf("%d %d %d", &n, &m, &k); 11 rep(i, 1, n) rep(j, 1, m) { 12 scanf("%d", &t); 13 s[i + j - 1][i - j + m] = t; 14 } 15 rep(i, 1, n + m - 1) rep(j, 1, m + n - 1) 16 s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; 17 rep(i, k, n + 1 - k) rep(j, k, m + 1 - k) { 18 tmp = 0, p = i + j - 1, q = i - j + m; 19 rep(r, 0, k - 1) tmp += s[p + r][q + r] - s[p - r - 1][q + r] - s[p + r][q - r - 1] + s[p - r - 1][q - r - 1]; 20 if(tmp > ans) ans = tmp, ax = i, ay = j; 21 } 22 printf("%d %d", ax, ay); 23 return 0; 24 }