2017-3-01 test
三道好像都是HDU上的题QAQ
题目名称都没改,差评
T1:http://acm.hdu.edu.cn/showproblem.php?pid=5073
被卡精度了QAQ
先排一发序,然后发现最后未动过的点一定是一段连续的区间,且其他点都被移动至其平均数处
所以直接O(n)乱搞即可
P.S.HDU上好像不能用long double
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int Mx=50010; int n,k; long double ans,tmp,sum,ave,a[Mx]; bool cmp(long double a,long double b) { return a<b; } int main() { int T; scanf("%d",&T); for(int t=1;t<=T;t++) { printf("Case #%d:\n",t); tmp=0,sum=0; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%LF",&a[i]); if(n==k) { cout<<"0.000000"<<endl; continue; } sort(a+1,a+1+n,cmp); for(int i=1;i<=n-k;i++) tmp+=a[i]*a[i],sum+=a[i];ave=sum/(n-k); ans=tmp-2*ave*sum+(n-k)*ave*ave; for(int l=1,r=n-k+1;r<=n;l++,r++) { tmp+=a[r]*a[r]-a[l]*a[l]; sum+=a[r]-a[l]; ave=sum/(n-k); ans=min(ans,tmp-2*ave*sum+(n-k)*ave*ave); } printf("%.8LF\n",ans); } return 0; }
T2:http://acm.hdu.edu.cn/showproblem.php?pid=5833
一言不合就数论QAQ
首先先预处理2000以内的素数,然后将a[]质因数分解
我们发现,一个完全平方数的各个质因子都是偶数次方,所以每次乘起来就等价于把系数^1
所以可以构造转移矩阵,第i行j列表示第j个素数在a[i]中的系数%2
高斯一发然后答案即为pow(2,自由元的个数)-1,记得开long long
P.S.自由元:消完之后一行都是0
#include <cstdio> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int Mx=2010; const long long p=1e9+7; int n,cnt,pr[Mx],vis[Mx],tran[310][310]; void pre() { for(int i=2;i<=2000;i++) { int jud=1; for(int j=2;j*j<=i;j++) if(i%j==0) jud=0; if(jud) pr[++cnt]=i; } } long long power(long long a,long long b) { long long c=1; while(b) { if(b&1) c=c*a%p; a=a*a%p; b>>=1; } return c; } int gauss() { int i=1; for(int j=1;i<=cnt&&j<=n;i++,j++) { int tmp=i; for(int k=i+1;k<=cnt;k++) if(tran[k][j]>tran[tmp][j]) tmp=k; if(tmp!=i) for(int k=j;k<=n+1;k++) swap(tran[tmp][k],tran[i][k]); if(tran[i][j]==0) { i--; continue; } for(int k=i+1;k<=cnt;k++) { if(!tran[k][j]) continue; for(int l=j;l<=n+1;l++) tran[k][l]=tran[k][l]^tran[i][l]; } } return n-(i-1); } int main() { pre(); int T; scanf("%d",&T); for(int t=1;t<=T;t++) { memset(tran,0,sizeof(tran)); printf("Case #%d:\n",t); scanf("%d",&n); for(int i=1;i<=n;i++) { long long x; scanf("%lld",&x); for(int j=1;j<=cnt;j++) { int tot=0; while(x%pr[j]==0) x/=pr[j],tot++; tran[j][i]=tot&1; } } printf("%lld\n",(long long) power(2,gauss())-1); } return 0; }
T3:http://acm.hdu.edu.cn/showproblem.php?pid=5770
好麻烦啊QAQ调了半天调不出来只能把std放上去了QAQ
orz ZSQ:http://blog.csdn.net/v5zsq/article/details/52170616
对于一组钥匙和宝箱u,v及其lca,我们可以分类讨论,有以下四种情况
1、u!=lca&&v!=lca:要想拿到宝箱,起点必须在u的子树中,终点必须在v的子树中
2、u==lca:起点不能在u的子树中,终点必须在v的子树中
3、v==lca:起点不能在v的子树中,终点必须在v的子树中
4、u==v:起点和终点在lca的不同子树中 或 起点or终点在lca的子树中,另一个点不在lca的子树中
这种情况为保证复杂度所以要反过来求不包含该节点的路径
①起点和终点都在lca的同一个儿子中
②起点和终点都不在在lca的子树中,即起点和终点x的dfs序都满足(x<l || x>r)
考虑维护DFS序,将以i为根的子树处理成一个区间[l,r],则每个宝箱可以映射为一个带权矩阵,对应上述情况
建立一个二维平面,平面上的点(x,y)表示从x走到y的价值,点权即为包含该点的所有矩阵的和
最后用扫描线+线段树即可解决
默默吐槽一下,std代码好吃藕啊QAQ(逃~
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; const int N = 200010; int to[N << 1], nxt[N << 1], head[N], cnt; void add(int x, int y){ to[++ cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; to[++ cnt] = x; nxt[cnt] = head[y]; head[y] = cnt; } struct Rec{ int x1, x2, y1, y2, val; }rec[N * 10]; struct Event{ int l, r, y, val, rank; }events[N * 10]; bool operator < (const Event &a, const Event &b){ return a.y < b.y || (a.y == b.y && a.rank < b.rank); } struct treasure{ int key, chest, val; }a[N]; int st[N], ed[N], n, m, dfs_clock, dep[N], fa[N][20]; int LCA(int x, int y){ if (dep[x] < dep[y]) swap(x, y); int t = dep[x] - dep[y]; for(int i = 0; i < 20; i ++) if (t >> i & 1) x = fa[x][i]; for(int i = 19; i >= 0; i --) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; if (x == y) return x; return fa[x][0]; } void dfs(int x){ st[x] = ++ dfs_clock; for(int i = 1; (1 << i) <= dep[x]; i ++) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for(int i = head[x]; i; i = nxt[i]) if (st[to[i]] == 0){ dep[to[i]] = dep[x] + 1; fa[to[i]][0] = x; dfs(to[i]); } ed[x] = dfs_clock; } struct node{ int tag, max; }t[N << 2]; #define mid ((l + r) >> 1) #define L (o << 1) #define R (o << 1 | 1) #define lch L, l, mid #define rch R, mid + 1, r void Push_up(int o){ t[o].max = max(t[L].max, t[R].max); } void change(int o, int v){ t[o].tag += v; t[o].max += v; } void Push_down(int o){ if (t[o].tag){ change(L, t[o].tag); change(R, t[o].tag); t[o].tag = 0; } } void update(int o, int l, int r, int ql, int qr, int v){ if (ql > qr) return; if (ql <= l && qr >= r) change(o, v); else{ Push_down(o); if (ql <= mid) update(lch, ql, qr, v); if (qr > mid) update(rch, ql, qr, v); Push_up(o); } } int main(){ int T, cs = 0; scanf("%d", &T); while(cs < T){ printf("Case #%d: ", ++ cs); memset(head, 0, sizeof head); memset(st, 0, sizeof st); memset(fa, 0, sizeof fa); memset(dep, 0, sizeof dep); memset(t, 0, sizeof t); cnt = dfs_clock = 0; scanf("%d%d", &n, &m); int x, y; for(int i = 1; i < n; i ++){ scanf("%d%d", &x, &y); add(x, y); } dfs(1); // for(int i = 1; i <= n; i ++) printf("st[%d] = %d ed[%d] = %d\n", i, st[i], i, ed[i]); int tot = 0, num = 0, ans = 0, tmp = 0; for(int i = 1; i <= m; i ++){ scanf("%d%d%d", &a[i].key, &a[i].chest, &a[i].val); int lca = LCA(a[i].key, a[i].chest); if (a[i].key == a[i].chest){ tmp += a[i].val; for(int j = head[a[i].key]; j; j = nxt[j]) if (to[j] != fa[a[i].key][0]){ rec[++ tot] = (Rec){st[to[j]], ed[to[j]], st[to[j]], ed[to[j]], -a[i].val}; } if (1 <= st[a[i].key] - 1 && ed[a[i].key] + 1 <= n){ rec[++ tot] = (Rec){1, st[a[i].key] - 1, ed[a[i].key] + 1, n, -a[i].val}; rec[++ tot] = (Rec){ed[a[i].key] + 1, n, 1, st[a[i].key] - 1, -a[i].val}; } if (1 <= st[a[i].key] - 1) rec[++ tot] = (Rec){1, st[a[i].key] - 1, 1, st[a[i].key] - 1, -a[i].val}; if (ed[a[i].key] + 1 <= n) rec[++ tot] = (Rec){ed[a[i].key] + 1, n, ed[a[i].key] + 1, n, -a[i].val}; }else if (a[i].key == lca){ for(int j = head[a[i].key]; j; j = nxt[j]) if (to[j] != fa[a[i].key][0] && LCA(to[j], a[i].chest) == to[j]){ y = to[j]; break; } if (1 <= st[y] - 1) rec[++ tot] = (Rec){1, st[y] - 1, st[a[i].chest], ed[a[i].chest], a[i].val}; if (ed[y] + 1 <= n) rec[++ tot] = (Rec){ed[y] + 1, n, st[a[i].chest], ed[a[i].chest], a[i].val}; }else if (a[i].chest == lca){ for(int j = head[a[i].chest]; j; j = nxt[j]) if (to[j] != fa[a[i].chest][0] && LCA(to[j], a[i].key) == to[j]){ y = to[j]; break; } if (1 <= st[y] - 1) rec[++ tot] = (Rec){st[a[i].key], ed[a[i].key], 1, st[y] - 1, a[i].val}; if (ed[y] + 1 <= n) rec[++ tot] = (Rec){st[a[i].key], ed[a[i].key], ed[y] + 1, n, a[i].val}; }else{ rec[++ tot] = (Rec){st[a[i].key], ed[a[i].key], st[a[i].chest], ed[a[i].chest], a[i].val}; } // if (rec[tot].x1 == 0) printf("%d %d %d lca = %d\n", a[i].key, a[i].chest, a[i].val, lca); } // for(int i = 1; i <= tot; i ++) // printf("%d %d %d %d %d\n", rec[i].x1, rec[i].x2, rec[i].y1, rec[i].y2, rec[i].val); int tt = 0; for(int i = 1; i <= tot; i ++){ // if (rec[i].x1 == 0 && rec[i].x2 == 0) printf("%d\n", ++ tt); events[++ num] = (Event){rec[i].x1, rec[i].x2, rec[i].y1, rec[i].val, 1}; events[++ num] = (Event){rec[i].x1, rec[i].x2, rec[i].y2 + 1, -rec[i].val, 0}; } sort(events + 1, events + num + 1); for(int i = 1; i <= num; i ++){ if (events[i].y > events[i - 1].y || i == 1) ans = max(ans, t[1].max); update(1, 1, n, events[i].l, events[i].r, events[i].val); if (i == num) ans = max(ans, t[1].max); // printf("%d\n", t[1].max); } printf("%d\n", ans + tmp); } return 0; }