题解链接:http://www.cygmasot.com/index.php/2015/09/23/codeforces_580/
题意:the length of the maximum non-decreasing subsegment
直接搞,水题
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <queue>
#include <set>
using namespace std;
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if (x>9) pt(x / 10);
putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 1e9;
const int N = 1e5+10;
int n;
int a[N];
int main() {
rd(n);
for (int i = 1; i <= n; i++)rd(a[i]);
int ans = 1;
for (int i = 2, pre = 1; i <= n; i++) {
if (a[i] >= a[i - 1]) {
pre++;
}
else pre = 1;
ans = max(ans, pre);
}pt(ans);
return 0;
}
题意:有一个双关键字的数组,共n个元素。常数d
选任意个使得选出的元素中 第一关键字(最大的-最小的)<d
并且使得第二关键字和最大。
问:最大的和是多少。
思路:
先排个序,然后two pointers搞搞,枚举左端点,右端点是单调的。
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <queue>
#include <set>
using namespace std;
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if (x>9) pt(x / 10);
putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 1e9;
const int N = 1e5+10;
int n, d;
pii a[N];
ll sum[N];
int main() {
rd(n); rd(d);
for (int i = 1; i <= n; i++) {
rd(a[i].first); rd(a[i].second);
}
sort(a + 1, a + 1 + n);
sum[0] = 0;
for (int i = 1; i <= n; i++)sum[i] = sum[i - 1] + a[i].second;
ll ans = a[1].second;
int r = 1;
for (int i = 1; i <= n; i++) {
while (r+1 <= n && a[r+1].first - a[i].first < d)r++;
ans = max(ans, sum[r] - sum[i - 1]);
}
pt(ans);
return 0;
}
题意:给定n个点的数 常数m
下面n个数给出点权(点权为0或1)
要求从根走到叶子节点的最短路径上 连续1的个数不超过m个 的叶子节点有多少个。
思路:
dfs直接搞就好了。
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <queue>
#include <set>
using namespace std;
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if (x>9) pt(x / 10);
putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 1e9;
const int N = 1e5+10;
int n, m;
int a[N];
vector<int>G[N];
int ans;
void dfs(int u, int fa, int val) {
if(a[u] == 1)
val += a[u];
else val = 0;
if (val > m)return;
if (u != fa && G[u].size() == 1)
{
ans++;
}
for (auto v : G[u]) {
if (v == fa)continue;
dfs(v, u, val);
}
}
int main() {
rd(n); rd(m);
for (int i = 1; i <= n; i++)rd(a[i]);
for (int i = 1, u, v; i < n; i++) {
rd(u); rd(v);
G[u].push_back(v); G[v].push_back(u);
}
ans = 0;
dfs(1, 1, 0);
pt(ans);
return 0;
}
n个点 m条有向边 选恰好k个点
下面n个数给出点权。
下面m行给出边和边权。
设上一次选的点是u
这一次选的点是v,则可以获得边权u->v的价值。
问:使得选出的权和最大,问最大的权和。
思路:显然是状压dp
dp[i][j]表示选的点状态为i,最后一次选的点是j的最大价值。
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <queue>
#include <set>
using namespace std;
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if (x>9) pt(x / 10);
putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 1e9;
const int N = 20;
int n, m, k;
int cnt(int x) {
int ans = 0;
while (x) { ans += x & 1; x >>= 1; }return ans;
}
int a[N];
int b[N][N];
ll dp[1 << 18][18];
bool vis[1 << 18][18];
int main() {
rd(n); rd(m); rd(k);
for (int i = 0; i < n; i++)rd(a[i]);
while (k--) {
int u, v, d;
rd(u); rd(v); rd(d); b[u-1][v-1] = d;
}
queue<pii> q;
for (int i = 0; i < n; i++) {
dp[1 << i][i] = a[i];
q.push({ 1 << i,i });
vis[1 << i][i] = 1;
}
ll ans = 0;
while (!q.empty()) {
auto u = q.front(); q.pop();
if (cnt(u.first) == m) {
ans = max(ans, dp[u.first][u.second]);
continue;
}
for (int i = 0; i < n; i++) {
if (!(u.first & (1 << i)))
{
pii v = { u.first | (1 << i), i };
ll now = dp[u.first][u.second] + b[u.second][i] + a[i];
dp[v.first][v.second] = max(dp[v.first][v.second], now);
if (!vis[v.first][v.second]) {
vis[v.first][v.second] = 1;
q.push(v);
}
}
}
}
pt(ans);
return 0;
}
题意:
给定n m k。
下面长度为n的数字串。
下面m+k个操作。
1 l r c:把区间[l,r]的所有字符改成c
2 l r d:询问区间[l,r]是否为周期d
(所谓周期 x 就是 (1 ≤ x ≤ |s|), if si = si + x for all i from 1 to |s| - x.)
对于每个询问输出YES or NO
思路:
首先是一个结论:若字符串s(下标为:[1,len])具有周期性x
那么 [1+x,len] == [1,len-x]
这个可以简单证明得到,不再重复证明。
因此我们需要动态获得区间的Hash值。
所以用线段树维护区间Hash值.
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <queue>
#include <set>
using namespace std;
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if (x>9) pt(x / 10);
putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 1e8;
const int MAGIC = 311, MOD = 1e9 + 7;
const int N = 1e5 + 10;
#define L(x) tree[x].l
#define R(x) tree[x].r
#define ls (id<<1)
#define rs (id<<1|1)
#define H(x) tree[x].hash
#define La(x) tree[x].lazy
#define Len(x) tree[x].len
int base[N];
int p[10][N];
int a[N];
struct Node {
int l, r, hash, lazy, len;
}tree[N << 2];
void up(int id) {
H(id) = ((ll)H(ls) * base[Len(rs)] % MOD + H(rs)) % MOD;
}
void go(int id, int val) {
La(id) = val;
H(id) = p[val][Len(id)];
}
void down(int id) {
if (La(id) != -1) {
go(ls, La(id));
go(rs, La(id));
La(id) = -1;
}
}
void build(int l, int r, int id) {
L(id) = l; R(id) = r; Len(id) = r - l + 1;
La(id) = -1;
if (l == r) {
H(id) = p[a[l]][1];
return;
}
int mid = (l + r) >> 1;
build(l, mid, ls); build(mid + 1, r, rs);
up(id);
}
void change(int l, int r, int val, int id) {
if (l == L(id) && R(id) == r) {
go(id, val);
return;
}
down(id);
int mid = (L(id) + R(id)) >> 1;
if (r <= mid)
change(l, r, val, ls);
else if (mid < l)
change(l, r, val, rs);
else {
change(l, mid, val, ls);
change(mid + 1, r, val, rs);
}
up(id);
}
int query(int l, int r, int id) {
if (l == L(id) && R(id) == r) {
return H(id);
}
down(id);
int mid = (L(id) + R(id)) >> 1;
int ok;
if (r <= mid)
ok = query(l, r, ls);
else if (mid < l)
ok = query(l, r, rs);
else {
ok = query(l, mid, ls);
ok = ((ll)ok * base[r-mid] % MOD + query(mid + 1, r, rs)) % MOD;
}
up(id);
return ok;
}
int n, m, k;
char str[N];
int main() {
base[0] = 1;
for (int i = 1; i < N; ++i) base[i] = ((ll)base[i - 1] * MAGIC) % MOD;
for (int i = 0; i < 10; i++) {
p[i][0] = 0;
for (int j = 1; j < N; j++)p[i][j] = ((ll)p[i][j - 1] * MAGIC%MOD + i) % MOD;
}
rd(n); rd(m); rd(k);
scanf("%s", str + 1);
for (int i = 1; i <= n; i++)a[i] = str[i]-'0';
build(1, n, 1);
k += m;
while (k--) {
int op, l, r, c;
rd(op); rd(l); rd(r); rd(c);
if (op == 1)
change(l, r, c, 1);
else {
if (l > r-c || l+c>r) { puts("YES");continue; }
ll x = query(l, r - c, 1), y = query(l + c, r, 1);
x == y ? puts("YES") : puts("NO");
}
}
return 0;
}