【2017.11.06】noip 赛前集训 | T1 洗澡、T2 日记【二分 + 前缀和】
T1 洗澡
洗澡的地方,有一段括号序列,将一个括号修改一次需要1的代价(将左括 号变成右括号或者相反),求最小代价使得括号序列合法
第一次(40)的代码:
这时候想着把括号分成三个部分:
①配对成功的() 这部分直接用栈不停 push / pop 即可。
②无法配对的 ) 这一部分用 ans 来记录
③无法配对的( 就是栈中剩下的部分。
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
int ans;
std::stack<char> st;
std::string s;
int main() {
freopen("shower.in", "r", stdin);
freopen("shower.out", "w", stdout);
std::cin >> s;
int len = s.length();
for (int i = 0; i < len; i++) {
if (s[i] == '(') st.push(s[i]);
if (s[i] == ')') {
if (st.empty()) {
ans++;
// st.push('(');
continue;
} else {
st.pop();
}
}
}
ans = ans >= 2 ? ans/2 : ans;
int ans_ = 0;
printf("%d\n", ans);
while (!st.empty()) {
ans_++;
st.pop();
}
ans_ = ans_ >= 2 ? ans_/2 : ans_;
printf("%d\n", ans + ans_);
return 0;
}
本来想关上文件的,打 fclose 打到一半去干别的事.....妥妥的CE。
看了正解,其实只要把没办法配对的 )看成( 就好了。
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
int ans;
std::stack<char> st;
std::string s;
int main() {
freopen("shower.in", "r", stdin);
freopen("shower.out", "w", stdout);
std::cin >> s;
int len = s.length();
for (int i = 0; i < len; i++) {
if (s[i] == '(') st.push(s[i]);
if (s[i] == ')') {
if (st.empty()) {
ans++;
st.push('(');
continue;
} else {
st.pop();
}
}
}
// ans = ans >= 2 ? ans/2 : ans;
int ans_ = 0;
// printf("%d\n", ans);
while (!st.empty()) {
ans_++;
st.pop();
}
ans_ = ans_ >= 2 ? ans_/2 : ans_;
printf("%d\n", ans + ans_);
return 0;
}
其实,不用栈(dalao太神了%%%%)。
#include <cstdio>
#include <cstring>
#include <iostream>
std::string s;
int ans;
int main() {
// freopen("shower.in", "r", stdin);
// freopen("shower.out", "w", stdout);
std::cin >> s;
int len = s.length() - 1, l = 0;
for (int i = 0; i <= len; i++) {
if (s[i] == '(') l++;
if (s[i] == ')') {
if (l > 0) l--;
else ans++, l++; // 把 )翻转成 (
}
}
printf("%d\n", ans + l / 2);
return 0;
}
T2 日记
日记之中,写满了质数,两个质数之间如果没有其他质数,那么则称为相邻的质数。给定𝑁,𝑘,询问不超过𝑁的数中能够表示成连续𝑘个质数之和的最大的数是多少。
下面是我一点也不优美的蜜汁做法,筛素数(O(nloglogn)),没二分,用了前缀和。
测试结果MLE,因为之前在MAXN上乘了二
,现在已经改过来了。
#include <cstdio>
#include <ctime>
#include <iostream>
#define ll long long
const int MAXN = 1e7 + 7;
int prime[MAXN], cnt = 1, T, n, k;
ll sum[MAXN];
bool ma[MAXN];
int read() {
int x = 0;
char ch = getchar();
while (ch > '9' || ch < '0') ch = getchar();
while (ch <= '9' && ch >= '0') x = x * 10 + ch -'0', ch = getchar();
return x;
}
int main() {
freopen("diary.in", "r",stdin);
freopen("diary.out", "w", stdout);
// clock_t start_time=clock();
//预处理 :
ma[2] = 1;
for (int i = 3; i <= MAXN; i++)
if (i % 2 == 0) ma[i] = 0;
else ma[i] = 1;
for (ll i = 3; i <= MAXN; i++)
if (ma[i])
for (ll j = i * i; j <= MAXN; j += i)
ma[j] = 0;
for(int i = 1; i <= MAXN; i++)
if (ma[i]) prime[cnt] = i, sum[cnt] = prime[cnt] + sum[cnt - 1], cnt++;
// for (int i = 1; i <= 1000; i++) printf("%d ", sum[i]);
// printf("%d\n", cnt);
T = read();
while (T--) {
n = read(); k = read();
if (k == 1) {
int i = cnt < n / 2 ? cnt - 1 : n / 2;
while (prime[i] > n) i--;
printf("%d\n", prime[i]);
} else {
int ma_2 = 2;
int add2 = prime[2] + prime[1];
while (add2 <= n) {
ma_2++; // 小于等于 n 的二数和的最大的那个两个数中大的数的坐标。
add2 = prime[ma_2] + prime[ma_2 - 1];
}
while (sum[ma_2] - sum[ma_2 - k] > n) {
ma_2--;
}
if(ma_2 < k) printf("-1\n");
else printf("%lld\n", sum[ma_2] - sum[ma_2 - k]);
}
}
// clock_t end_time=clock();
// std::cout<< "Running time is: "<<static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000<<"ms"<<"\n";//输出运行时间
return 0;
}
现在来研究一下二分的做法。%%%dalao!!!!
#include <cstdio>
#define ll long long
const int MAXN = 1e7 + 7;
int T, cnt = 1; // 注意 cnt 的初始值
ll prime[MAXN], sum[MAXN];
bool ma[MAXN];
void is_prime() {
ma[2] = 1;
for (int i = 3; i <= MAXN; i++)
if (i % 2 == 0) ma[i] = 0;
else ma[i] = 1;
for (ll i = 3; i <= MAXN; i++)
if (ma[i])
for (ll j = i * i; j <= MAXN; j += i)
ma[j] = 0;
for(int i = 1; i <= MAXN; i++)
if (ma[i]) prime[cnt] = i, sum[cnt] = prime[cnt] + sum[cnt - 1], cnt++;
}
ll work(int n, int k) {
int l = k - 1, r = cnt;
while (r - l > 1) {
int mid = l + r >> 1;
if (sum[mid] - sum[mid - k] <= n) l = mid;
else r = mid;
}
if (l < k) return -1;
return sum[l] - sum[l - k];
}
int main() {
freopen("diary.in", "r", stdin);
freopen("diary.out", "w", stdout);
is_prime();
// for (int i = 1; i <= 100; i++) printf("%d ", prime[i]);
scanf("%d", &T);
while (T--) {
int n, k;
scanf("%d%d", &n, &k);
printf("%lld\n", work(n, k));
}
return 0;
}

浙公网安备 33010602011771号