A:hdoj 5690 All X
打个表看了看,发现循环最大不超过k,因为k最大为10000,就先暴力找一下,最多找k次。我们边找边记录结果,若发现相同的就说明找到一个循环节,直接跳出即可。
AC代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 3 * 1e6 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
LL ans[100000 + 1];
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
LL x, m, k, c; scanf("%I64d%I64d%I64d%I64d", &x, &m, &k, &c);
//printf("%d\n", Solve(x, k, m));
LL top = 1, sum = x % k, l = 1, r = 1;
ans[1] = sum;
for(;;) {
sum = (sum * 10 + x) % k;
bool flag = false;
for(int i = 1; i <= top; i++) {
if(sum == ans[i]) {
l = i;
flag = true;
break;
}
}
if(flag) break;
ans[++top] = sum;
if(top >= m) {
break;
}
}
bool flag;
if(top >= m) {
flag = (ans[m] == c);
}
else {
r = top; m -= l - 1; m %= (r - l + 1);
if(m == 0) m = r - l + 1;
flag = (ans[l + m - 1] == c);
}
printf("Case #%d:\n", kcase++);
printf(flag ? "Yes\n" : "No\n");
}
return 0;
}
B:hdoj 5691 Sitting in Line
状压dp
dp[i][j][s]
表示第i个位置选第j个人且已经就坐的人状态为s
没想到这都过了 (ˇˍˇ) 想~
AC代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = -2 * 1e9;
int dp[18][18][1<<18];
int vis[18];
int b[18], a[18], p[18];
int main()
{
for(int i = 0; i <= 17; i++) {
b[i] = (1<<i);
}
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int N; scanf("%d", &N);
for(int i = 0; i < N; i++) vis[i] = -1;
for(int i = 0; i < N; i++) {
scanf("%d%d", &a[i], &p[i]);
if(p[i] != -1) vis[p[i]] = i;
}
for(int i = 0; i < N; i++) {
for(int j = 0; j < N; j++) {
for(int s = 0; s < b[N]; s++) {
dp[i][j][s] = INF;
}
}
}
if(vis[0] == -1) {
for(int i = 0; i < N; i++) {
if(p[i] != -1) continue;
dp[0][i][b[i]] = 0;
}
}
else dp[0][vis[0]][b[vis[0]]] = 0;
for(int i = 0; i < N-1; i++) {
for(int j = 0; j < N; j++) {
for(int s = 0; s < b[N]; s++) {
if(dp[i][j][s] == INF) continue;
if(vis[i+1] != -1) {
if(!(s & b[vis[i+1]])) {
int ns = s | b[vis[i+1]];
dp[i+1][vis[i+1]][ns] = max(dp[i+1][vis[i+1]][ns], dp[i][j][s] + a[j] * a[vis[i+1]]);
}
continue;
}
for(int k = 0; k < N; k++) {
if(p[k] != -1) continue;
if(!(s & b[k])) {
int ns = s | b[k];
dp[i+1][k][ns] = max(dp[i+1][k][ns], dp[i][j][s] + a[j] * a[k]);
}
}
}
}
}
int ans = INF;
for(int i = 0; i < N; i++) {
ans = max(ans, dp[N-1][i][b[N]-1]);
}
printf("Case #%d:\n", kcase++);
printf("%d\n", ans);
}
return 0;
}
C:hdoj 5692 Snacks
第一眼感觉是树链剖分,后来发现一直从0节点出发,就是裸的DFS + 线段树区间更新。时间真的不够用了。。。
AC代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef __int64 LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
struct Tree {
int l, r, len;
LL lazy, Max;
};
Tree tree[MAXN<<2];
LL sval[MAXN];
LL val[MAXN];
int vs[MAXN], node[MAXN], dfs_clock;
int num[MAXN];
void PushUp(int o) {
tree[o].Max = max(tree[ll].Max, tree[rr].Max);
}
void PushDown(int o) {
if(tree[o].lazy) {
tree[ll].lazy += tree[o].lazy;
tree[rr].lazy += tree[o].lazy;
tree[ll].Max += tree[o].lazy;
tree[rr].Max += tree[o].lazy;
tree[o].lazy = 0;
}
}
void Build(int o, int l, int r) {
tree[o].l = l; tree[o].r = r;
tree[o].len = r - l + 1; tree[o].lazy = 0;
if(l == r) {
tree[o].Max = sval[node[l]];
return ;
}
int mid = (l + r) >> 1;
Build(ll, l, mid); Build(rr, mid+1, r);
PushUp(o);
}
void Update(int o, int L, int R, LL v) {
if(tree[o].l == L && tree[o].r == R) {
tree[o].lazy += v;
tree[o].Max += v;
return ;
}
PushDown(o);
int mid = (tree[o].l + tree[o].r) >> 1;
if(R <= mid) Update(ll, L, R, v);
else if(L > mid) Update(rr, L, R, v);
else {
Update(ll, L, mid, v);
Update(rr, mid+1, R, v);
}
PushUp(o);
}
LL Query(int o, int L, int R) {
if(tree[o].l == L && tree[o].r == R) {
return tree[o].Max;
}
PushDown(o);
int mid = (tree[o].l + tree[o].r) >> 1;
if(R <= mid) return Query(ll, L, R);
else if(L > mid) return Query(rr, L, R);
else return max(Query(ll, L, mid), Query(rr, mid+1, R));
}
struct Edge {
int from, to, next;
};
Edge edge[MAXN * 2];
int head[MAXN], edgenum;
void init() { edgenum = 0; CLR(head, -1); }
void addEdge(int u, int v) {
Edge E = {u, v, head[u]};
edge[edgenum] = E;
head[u] = edgenum++;
}
void DFS(int u, int fa) {
if(vs[u] == -1) {
vs[u] = ++dfs_clock;
node[dfs_clock] = u;
}
num[u] = 1;
if(fa != -1) sval[u] = val[u] + sval[fa];
else sval[u] = val[u];
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(v == fa) continue;
DFS(v, u);
num[u] += num[v];
}
}
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int N, Q; scanf("%d%d", &N, &Q); init();
for(int i = 0; i < N-1; i++) {
int u, v; scanf("%d%d", &u, &v);
addEdge(u, v); addEdge(v, u);
}
for(int i = 0; i < N; i++) scanf("%I64d", &val[i]), vs[i] = -1;
dfs_clock = 0; DFS(0, -1); Build(1, 1, N);
printf("Case #%d:\n", kcase++);
while(Q--) {
int op, x; LL y;
scanf("%d", &op);
if(op == 0) {
scanf("%d%I64d", &x, &y);
Update(1, vs[x], vs[x] + num[x] - 1, y - val[x]);
val[x] = y;
}
else {
scanf("%d", &x);
//cout << vs[x] << ' ' << vs[x] + num[x] - 1 << endl;
printf("%I64d\n", Query(1, vs[x], vs[x] + num[x] - 1));
}
}
}
return 0;
}
D:hdoj 5693 D Game
这个嘛,我估计补不了。(还是太SB)
E:hdoj 5694 BD String
用
f[i]
表示第
i
段的长度,
发现有这样的规律:
ansb[i]
统计前
i
位的
ansb[n]=ansb[s]+(ansd[f[s]]−ansd[f[s]−(n−f[s]−1)])+flag。
flag
对应的是当前要统计的信息,因为存在字符的翻转。最大的
s
满足
flag==true
统计字符
b
,反之统计字符
AC代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = -2 * 1e9;
LL f[70], fb[70], fd[70];
LL DFS(LL n, bool flag) {
if(n == 0) return 0;
if(n == 1) return flag;
int s;
for(int i = 1; i <= 60; i++) {
if(f[i] == n) {
return flag ? fb[i] : fd[i];
}
if(f[i] > n) {
s = i - 1; break;
}
}
LL sum = flag ? fb[s] : fd[s];
LL R = f[s], L = R - (n - f[s] - 1) + 1;
//cout << n << ' ' << L << ' ' << R << endl;
return sum + DFS(R, !flag) - DFS(L - 1, !flag) + flag;
}
int main()
{
f[1] = 1; fd[1] = 0; fb[1] = 1;
for(int i = 2; i <= 60; i++) {
f[i] = f[i-1] * 2 + 1;
fb[i] = fb[i-1] + 1 + fd[i-1];
fd[i] = fb[i-1] + fd[i-1];
//cout << f[i] << ' ' << i << endl;
}
int t, kcase = 1; scanf("%d", &t);
while(t--) {
LL L, R; scanf("%I64d%I64d", &L, &R);
printf("%I64d\n", DFS(R, 1) - DFS(L-1, 1));
}
return 0;
}
F:hdoj 5695 Gym Class
建个有向图,然后就是维护一个最大堆的拓扑序。
半小时才去看。真是SB中的SB。
AC代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
vector<int> G[MAXN];
int in[MAXN];
int main()
{
int t; scanf("%d", &t);
while(t--) {
int n, m; scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) G[i].clear(), in[i] = 0;
for(int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v); in[v]++;
}
priority_queue<int, vector<int>, less<int> > Q;
for(int i = 1; i <= n; i++) {
if(in[i] == 0) {
Q.push(i);
}
}
LL ans = 0;
int Min = n + 1;
while(!Q.empty()) {
int u = Q.top(); Q.pop();
Min = min(Min, u);
ans += Min;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(--in[v] == 0) {
Q.push(v);
}
}
}
printf("%I64d\n", ans);
}
return 0;
}