Magic Pen 6
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 399 Accepted Submission(s): 166
At the end of this term, teacher gives Timer a job to deliver the list of N students who fail the course to dean's office. Most of these students are Timer's friends, and Timer doesn't want to see them fail the course. So, Timer decides to use his magic pen to scratch out consecutive names as much as possible. However, teacher has already calculated the sum of all students' scores module M. Then in order not to let the teacher find anything strange, Timer should keep the sum of the rest of students' scores module M the same.
Plans can never keep pace with changes, Timer is too busy to do this job. Therefore, he turns to you. He needs you to program to "save" these students as much as possible.
The first line of each case contains two integer N and M, (0< N <= 100000, 0 < M < 10000),then followed by a line consists of N integers a1,a2,...an (-100000000 <= a1,a2,...an <= 100000000) denoting the score of each student.(Strange score? Yes, in great HIT, everything is possible)
題意:有N個數, 取出一個區間的數。 該區間的和要能整除M。 求最大的區間
思路: 水過了。O(n ^ 2)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
//
const int V = 100000 + 50;
const int MaxN = 80 + 5;
const int mod = 10000 + 7;
const __int64 INF = 0x7FFFFFFFFFFFFFFFLL;
const int inf = 0x7fffffff;
int n, m, sum[V], ans;
int main() {
int i, j;
while(~scanf("%d%d", &n, &m)) {
ans = 0;
for(i = 1; i <= n; ++i) {
int temp;
scanf("%d", &temp);
sum[i] = (sum[i - 1] + temp) % m;
}
for(i = n; i >= 1 && i > ans; --i) {
for(j = 1; j + i - 1 <= n; ++j)
if((sum[j + i - 1] - sum[j - 1]) % m == 0) {
ans = max(ans, i);
break;
}
}
printf("%d\n", ans);
}
}
方法二: 貪心 O(NlogN)
比上面的N^2慢, 不知道是數據水, 還是可以證明區間一定很接近N.
題目是要求 (sum[i] - sum[j] )% m == 0
那麼只需要將每個 sum[i] % m 然後排序。 判斷該模的最大區間。
這裏的模一定是非負數, 坑了我很久 -2 % 8 = 6 而不是 -2.
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
//
const int V = 100000 + 50;
const int MaxN = 80 + 5;
const int mod = 10000 + 7;
const __int64 INF = 0x7FFFFFFFFFFFFFFFLL;
const int inf = 0x7fffffff;
pair<int, int> pa[V];
int n, m, ans;
int main() {
int i, j;
while(~scanf("%d%d", &n, &m)) {
ans = 0;
pa[0].first = pa[0].second = 0;
for(i = 1; i <= n; ++i) {
int temp;
scanf("%d", &temp);
pa[i].first = (pa[i - 1].first + temp) % m;
pa[i].first = (pa[i].first + m) % m;
pa[i].second = i;
}
sort(pa, pa + n + 1);
j = 0;
for(i = 1; i <= n; ++i) {
if(pa[i].first != pa[j].first)
j = i;
ans = max(ans, pa[i].second - pa[j].second);
}
printf("%d\n", ans);
}
}
方法三: O(N)
但是還是沒有方法一快。無解。
每次只更新模的左右區間。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
//
const int V = 100000 + 50;
const int MaxN = 80 + 5;
const int mod = 10000 + 7;
const __int64 INF = 0x7FFFFFFFFFFFFFFFLL;
const int inf = 0x7fffffff;
int n, m, ans, sum[V];
pair<int, int> Mod[V]; // 模i的區間 [Mod[i].first, Mod[i].second]
bool vis[V];
int main() {
int i, j;
while(~scanf("%d%d", &n, &m)) {
ans = 0;
memset(Mod, 0, sizeof(Mod));
memset(vis, false, sizeof(vis));
vis[0] = true;
for(i = 1; i <= n; ++i) {
int temp;
scanf("%d", &temp);
sum[i] = (sum[i - 1] + temp) % m;
sum[i] = (sum[i] + m) % m;
if(!vis[sum[i]]) {
vis[sum[i]] = true;
Mod[sum[i]].first = i;
}
else {
Mod[sum[i]].second = max(Mod[sum[i]].second, i);
ans = max(ans, Mod[sum[i]].second - Mod[sum[i]].first);
}
}
printf("%d\n", ans);
}
}