写个暴力程序会发现若n*r*c 是偶数,则是必败态,输出0.000000
否则对于3*3*3 赢的位置有:
1 0 1
0 1 0
1 0 1
0 1 0
1 0 1
0 1 0
1 0 1
0 1 0
1 0 1
1为必胜点。也就是说左上角是1,这样扩散出去。
答案就是所有1位置的概率和。
题解:点击打开链接
因为k很小
公式: ((dep[y]-dep[x])%k+1)*val
当确定depx后每隔k个深度增加的点权就是一个定值。
思路:
先dfs得到dfs序,然后建k个线段树,把(dep[i] - dep[1] )%k相同的放到一个线段树内操作。
当然我们不需要把点分开处理,因为只要查询时定位好点所在的线段树就可以了。
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l, mid, rt<<1
#define rson mid+1,r, rt<<1|1
typedef long long ll;
const int N =50000+10;
const int M = N+N;
//
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');
}
//
struct Edge {
int v, nex;
Edge() {
}
Edge(int _v, int _nex) {
v = _v; nex = _nex;
}
};
struct node {
ll v, addv;
};
struct Seg {
node a[N<<2];
void build(int l, int r, int rt) {
a[rt].v = a[rt].addv = 0;
if (l != r) {
int mid = (l+r)>>1;
build(lson); build(rson);
}
}
void Down(node& fa, node& ls, node& rs) {
if (fa.addv!=0) {
ls.addv += fa.addv;
ls.v += fa.addv;
rs.addv += fa.addv;
rs.v += fa.addv;
fa.addv = 0;
}
}
void update(int L, int R, ll v, int l, int r, int rt) {
if (L<=l && r<=R) {
a[rt].addv += v;
a[rt].v += v;
} else {
Down(a[rt], a[rt<<1], a[rt<<1|1]);
int mid = (l+r)>>1;
if (R<=mid)
update(L, R, v,lson);
else if (L>mid)
update(L, R, v,rson);
else {
update(L, mid, v, lson);
update(mid+1, R, v, rson);
}
}
}
void query(int pos, int l, int r, int rt) {
if (l == r) {
//putchar('-');
pt(a[rt].v);
putchar('\n');
} else {
Down(a[rt], a[rt<<1], a[rt<<1|1]);
int mid = (l+r)>>1;
if (pos<=mid)
query(pos, lson);
else
query(pos, rson);
}
}
}sol[5];
int T = 0, n, K, d[N];
int dep, pos[N], son[N];
int g[N], idx;
Edge e[M];
void add(int u, int v) {
e[idx] = Edge(v, g[u]);
g[u] = idx++;
}
void dfs(int v, int u, int fa) {
++ dep;
pos[u] = dep;
son[u] = 1;
d[u] = v%K;
for (int i = g[u]; ~i; i = e[i].nex)
if (e[i].v!=fa) {
dfs(v+1, e[i].v, u);
son[u] += son[e[i].v];
}
}
int sub(int x, int y) {
return ((y-x)%K+K)%K;
}
void work() {
int m, typ, x, u, v;
rd(n); rd(m); rd(K);
idx = 0;
memset(g, -1, sizeof(int)*(n+2));
for (int i = 0; i < n-1; ++i) {
rd(u); rd(v);
add(u, v); add(v, u);
}
dep = 0;
dfs(0, 1, -1);
for (int i = 0; i < K; ++i)
sol[i].build(1, n, 1);
printf("Case#%d:\n", ++T);
while (m-->0) {
scanf("%d", &typ);
if (typ == 1) {
rd(u); rd(v);
x = d[u];
for (int j = 0; j < K; ++j)
sol[j].update(pos[u], pos[u]+son[u]-1, (ll)(sub(x,j)+1)*v, 1, n, 1);
} else {
rd(u);
sol[d[u]].query(pos[u], 1, n, 1);
}
}
}
int main() {
int cas;
scanf("%d", &cas);
while (cas-->0) {
work();
}
return 0;
}
思路:
n^2的dp dp[i]表示前i个数的最大价值
dp[i] = max(dp[j] + (a[i]-a[j])*(a[i]-a[j]));
思路:
我们先把礼物平均分成2堆。
然后枚举1-(n/2)的所有二进制状态。0就给a,1就给b。
我们设此时a获得的价值和为A,b获得的价值和为B
那么对于一个状态我们就能得到 B-A。
给所有B-A排个序,得到数组K
对于另一半(n/2+1) - n也这样枚举得到A-B.然后去K数组中二分查找距离-(A-B)最近的数即可。
记忆化搜索,从个位开始构造
Lcm(1-9) = 2520
Codeforces 55D : 点击打开链接
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 105;
const int M = 3005;//LCM(1..9) = 2520;
int a[N], num[M], cnt;
ll dp[N][N][M];//dp[i][j][k]表示考虑后i位的lcm是j,和为k的数的个数
int gcd(int a, int b) {
while(a>0 && b>0) {
if(a > b) a = a%b;
else b = b%a;
}
return a+b;
}
void pre() {
cnt = 0;
for(int i = 1; i <= 2520; i ++) {
if(2520 % i == 0) {
num[i] = cnt++;
}
}
memset(dp, -1, sizeof dp);
}
ll dfs(int len, int lcm, int sum, bool f) {
if(len == 0) {
if(sum%lcm == 0) return 1;
else return 0;
}
if(!f && dp[len][num[lcm]][sum] != -1) {
return dp[len][num[lcm]][sum];
}
ll ans = 0;
int Max = f?a[len]:9;
for(int i = 0; i <= Max; i ++) {
int nlcm;
if(i == 0) nlcm = lcm;
else nlcm = lcm/__gcd(lcm, i)*i;
ans += dfs(len-1, nlcm, (sum *10 + i) % 2520, f && i == Max);
}
if(!f) dp[len][num[lcm]][sum] = ans;
return ans;
}
ll cal(ll n) {
int size = 0;
while(n > 0) {
a[++size] = n%10;
n /= 10;
}
ll ans = dfs(size, 1, 0, true);
return ans;
}
int main() {
pre();
int T; scanf("%d", &T);
while(T--) {
ll b;
cin>>b;
cout<<cal(b) - 1<<endl;
}
}
搜索+剪枝
题解:点击打开链接
圆桌骑士。poj 2942.白书上的原题。。最后答案改成 n-ans即可