FOJ有奖月赛-2014年11月 题解

来源:互联网 发布:网络位置是什么 编辑:程序博客网 时间:2024/04/29 07:25

Problem A: Yellowstar的第一道题

写个暴力程序会发现若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位置的概率和。

题解:点击打开链接

Problem B easy problem

因为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|1typedef 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);elsequery(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;}


Problem C ytaaa

思路:

n^2的dp dp[i]表示前i个数的最大价值

dp[i] = max(dp[j] + (a[i]-a[j])*(a[i]-a[j]));


Problem D 礼物分配

思路:

我们先把礼物平均分成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)最近的数即可。



Problem E chriswho

记忆化搜索,从个位开始构造

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;}}


Problem F 骑士

搜索+剪枝

题解:点击打开链接

Problem G 快来买肉松饼


圆桌骑士。poj 2942.白书上的原题。。最后答案改成 n-ans即可


1 0
原创粉丝点击