@wsndy-xx
2018-05-05T03:24:39.000000Z
字数 7431
阅读 1488
wsndy
题解小奇挖矿2(mining)
【题目背景】
小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎。
【问题描述】
现在有 个星球,从左到右标号为 到 ,小奇最初在 号星球。
有 处矿体,第 处矿体有 单位原矿,在第 个星球上。
由于飞船使用的是老式的跳跃引擎,每次它只能从第 号星球移动到第 号星球或 号星球。每到一个星球,小奇会采走该星球上所有的原矿,求小奇能采到的最大原矿数量。
注意,小奇不必最终到达 号星球。
【输入格式】
第一行 个整数 。
接下来 行,每行 个整数 。
【输出格式】
输出一行一个整数,表示要求的结果。
【样例输入】
3 13100 410 71 11
【样例输出】
101
【样例解释】
第一次从 到 ,第二次从 到 ,总共采到 单位原矿。
【数据范围】
对于20%的数据
对于40%的数据
对于60%的数据
对于100%的数据
小奇的矩阵(matrix)
【题目背景】
小奇总是在数学课上思考奇怪的问题。
【问题描述】
给定一个 的矩阵,矩阵中的每个元素 为正整数。
接下来规定
合法的路径初始从矩阵左上角出发,每次只能向右或向下走,终点为右下角。
路径经过的 个格子中的元素为 , 为 的平均数,路径的 值为
求 值最小的合法路径,输出V值即可,有多组测试数据。
【输入格式】
第一行包含一个正整数 ,表示数据组数。
对于每组数据:
第一行包含两个正整数 和 ,表示矩阵的行数和列数。
接下来 行,每行 个正整数 ,描述这个矩阵。
【输出格式】
对于每次询问,输出一行一个整数表示要求的结果
【样例输入】
12 21 23 4
【样例输出】
14
【数据范围】
对于30%的数据
有另外40%的数据 ,矩阵中的元素不大于
对于100%的数据 ,矩阵中的元素不大于
小奇的仓库(warehouse)
【题目背景】
小奇采的矿实在太多了,它准备在喵星系建个矿石仓库。令它无语的是,喵星系的货运飞船引擎还停留在上元时代!
【问题描述】
喵星系有 个星球,星球以及星球间的航线形成一棵树。
从星球 到星球 要花费 秒。( 表示 间的航线长度, 为位运算中的异或)
为了给仓库选址,小奇想知道,星球 到其它所有星球花费的时间之和。
【输入格式】
第一行包含两个正整数 。
接下来 行,每行 个正整数 ,表示 之间的航线长度为 。
【输出格式】
行,每行一个整数,表示星球 到其它所有星球花费的时间之和。
【样例输入】
4 01 2 11 3 21 4 3
【样例输出】
681012
【数据范围】
| 测试点编号 | N | M |
|---|---|---|
| 1 | 6 | 0 |
| 2 | 100 | 5 |
| 3 | 2000 | 9 |
| 4 | 50000 | 0 |
| 5 | 50000 | 0 |
| 6 | 50000 | 1 |
| 7 | 50000 | 6 |
| 8 | 100000 | 10 |
| 9 | 100000 | 13 |
| 10 | 100000 | 15 |
保证答案不超过
将所有矿物排序, 为到第 个矿体能获得的最大原矿数,那么 ,其中, 满足能拆分成 和 。
这样 需要 的复杂度,但是我们发现,相距超过 (Noip 2017 Day1 T1 Woc)的一定可达,那么不超过 的范围内暴力,超过 的取个最大值即可,复杂度
可以把相邻的星球距离超过 的压缩成 ,按照 的 做法
吐槽
竟然只能的 , 位置竟然可以重复,
#include<map>#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define inf 1000000000#define ll long longusing namespace std;ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}struct data{int a,b;friend bool operator<(data a,data b){return a.a<b.a;}}a[100005];int n,m;int v[2000005],f[2000005];int main(){memset(f,-1,sizeof(f));n=read();m=read();for(int i=1;i<=n;i++)a[i].b=read(),a[i].a=read();sort(a+1,a+n+1);int now=0;for(int i=1;i<=n;i++){if(a[i].a-a[i-1].a>17)now+=18,v[now]+=a[i].b;else now+=a[i].a-a[i-1].a,v[now]+=a[i].b;}int ans=0;f[0]=0;for(int i=0;i<=now;i++)if(f[i]!=-1){f[i+4]=max(f[i+4],f[i]+v[i+4]);f[i+7]=max(f[i+7],f[i]+v[i+7]);ans=max(ans,f[now]);}printf("%d\n",ans);return 0;}
对于30%的数据,把所有的路径深搜出来取最优,复杂度是
这道题乍一看像是 ,但是问题在于因为求的是方差与平均数有关,每一步的代价似乎不能直接得出
对于另外40%的数据,我们发现路径 和 不超过 ,考虑枚举 ,平均值为 ,那我们就能得到每一步的代价,但是要保证求的路径符合 和为,设计 表示到 ,和为 的最小代价
事实上,路径 和不等于 也无所谓,因为对于一条路径,只有我们枚举的 等于路径 和时,这条路径的方差才最小
设我们枚举的 比真实的 和小 , 是任意实数
很容易证明
所以直接去掉 的第一维,复杂度是 ,可以通过100%的数据
#include<map>#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#define inf 1000000000#define ll long long#define N (n+m)*30using namespace std;ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}int ans;int T,n,m;int a[35][35];int f[1805][35][35];void dp(){f[a[1][1]][1][1]=a[1][1]*a[1][1];for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)for(int k=0;k<=N;k++)if(f[k][i][j]!=1000000){int x=i+1,y=j,v=a[x][y];f[k+v][x][y]=min(f[k+v][x][y],f[k][i][j]+v*v);x=i,y=j+1,v=a[x][y];f[k+v][x][y]=min(f[k+v][x][y],f[k][i][j]+v*v);}for(int i=1;i<=N;i++)if(f[i][n][m]!=1000000)ans=min(ans,(n+m-1)*f[i][n][m]-i*i);}int main(){T=read();for(int cas=1;cas<=T;cas++){ans=inf;n=read();m=read();for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read();for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)for(int k=0;k<=N;k++)f[k][i][j]=1000000;dp();printf("%d\n",ans);}return 0;}
,就有10分
在 的基础上,我们对每条边处理一下 ,就有 分
简单的树形 ,或者 的 ,处理完每个点到其它点的最短路后再加上 , 分
第 个点无需 ,那么我们树形 扫一个节点与其它所有节点的路径长度之和,可以合并信息,最终均摊 ,分。
第 个点 ,那么我们树形 到一个点时记录有多少个 ,多少个 ,然后每当一条路径到 ,那部分就再记录一个值,分到手。
一样的,就是原来的、、大于等于 变成了 么, 分
为什么 的树剖会 掉 分
#include<set>#include<map>#include<ctime>#include<queue>#include<cmath>#include<cstdio>#include<vector>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>#define inf 1000000000#define pa pair<int,int>#define ll long long#define mod 45989using namespace std;int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}int bin[20];int n,m,cnt;int dis[100005],last[100005];int f[100005][16],g[100005],t[16];struct edge{int to,next,v;}e[200005];void insert(int u,int v,int w){e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=w;}void dfs1(int x,int fa){for(int i=last[x];i;i=e[i].next)if(e[i].to!=fa){dfs1(e[i].to,x);g[x]+=g[e[i].to]+e[i].v/16;f[x][e[i].v%16]++;for(int j=0;j<16;j++){int k=j+e[i].v;g[x]+=k/16*f[e[i].to][j];f[x][k%16]+=f[e[i].to][j];}}}void dfs2(int x,int fa){for(int i=last[x];i;i=e[i].next)if(e[i].to!=fa){int tmp=g[x]-g[e[i].to];for(int j=0;j<16;j++){int k=j+e[i].v;tmp-=k/16*f[e[i].to][j];t[k%16]=f[x][k%16]-f[e[i].to][j];}t[e[i].v%16]--;g[e[i].to]+=tmp;f[e[i].to][e[i].v%16]++;for(int j=0;j<16;j++){int k=j+e[i].v;g[e[i].to]+=k/16*t[j];f[e[i].to][k%16]+=t[j];}dfs2(e[i].to,x);}}int main(){bin[0]=1;for(int i=1;i<20;i++)bin[i]=bin[i-1]<<1;n=read(),m=read();for(int i=1;i<n;i++){int u=read(),v=read(),w=read();insert(u,v,w);}dfs1(1,0);dfs2(1,0);for(int i=1;i<=n;i++){ll ans=g[i]*16;for(int j=0;j<16;j++)ans+=(j^m)*f[i][j];printf("%I64d\n",ans);}return 0;}
//不知道咋WA的树剖#include <iostream>#include <cstdio>using namespace std;#define LL long longconst int N = 1e5 + 10;const int oo = 2e9;#define gc getchar()int n, m;LL f[105][105];inline int read() {int x = 0; char c = gc;while(c < '0' || c > '9') c = gc;while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;return x;}void Work_1() {for(int i = 1; i <= n; i ++)for(int j = 1; j <= n; j ++)f[i][j] = oo;for(int i = 1; i <= n; i ++)f[i][i] = 0;for(int i = 1; i < n; i ++) {int a = read(), b = read(), c = read();f[a][b] = f[b][a] = c;}for(int k = 1; k <= n; k ++)for(int i = 1; i <= n; i ++)for(int j = 1; j <= n; j ++)f[i][j] = min(f[i][k] + f[k][j], f[i][j]);/*for(int i = 1; i <= n; i ++) {for(int j = 1; j <= n; j ++)cout << f[i][j] << " ";cout << endl;}*/LL Answer(0);for(int i = 1; i <= n; i ++) {Answer = 0;for(int j = 1; j <= n; j ++) {Answer += (f[i][j] ^ m);}cout << Answer << endl;}}struct Node {int u, v, w, nxt;} G[4010];int head[N], topp[N], dis[N], fa[N], deep[N], size[N], son[N];int now = 1;inline void Add(int u, int v, int w) {G[now].v = v; G[now].w = w; G[now].nxt = head[u]; head[u] = now ++;}void Dfs_1(int u, int f_, int dep) {fa[u] = f_, deep[u] = dep;size[u] = 1;for(int i = head[u]; ~ i; i = G[i].nxt) {int v = G[i].v;if(v != f_) {dis[v] = dis[u] + G[i].w;Dfs_1(v, u, dep + 1);size[u] += size[v];if(size[v] > size[son[u]]) son[u] = v;}}}void Dfs_2(int u, int tp) {topp[u] = tp;if(!son[u]) return ;Dfs_2(son[u], tp);for(int i = head[u]; ~ i; i = G[i].nxt) {int v = G[i].v;if(v != fa[u] && v != son[u]) Dfs_2(v, v);}}inline int Lca(int x, int y) {int tp1 = topp[x], tp2 = topp[y];while(tp1 != tp2) {if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2);x = fa[tp1];tp1 = fa[x];}return deep[x] < deep[y] ? x : y;}void Work_2() {for(int i = 1; i <= n; i ++) head[i] = -1;for(int i = 1; i < n; i ++) {int u = read(), v = read(), w = read();Add(u, v, w); Add(v, u, w);}Dfs_1(1, 0, 1);Dfs_2(1, 1);for(int i = 1; i <= n; i ++) {LL Answer = 0;for(int j = 1; j <= n; j ++) {if(i == j) continue ;int lca = Lca(i, j);Answer += ((dis[i] + dis[j] - dis[lca] - dis[lca]) ^ m);}printf("%lld\n", Answer);}}int main() {freopen("warehouse.in", "r", stdin);freopen("warehouse.out", "w", stdout);n = read();m = read();if(n <= 100) Work_1();else if(n == 2000) Work_2();return 0;}
暴力都不知道咋
道 ,不擅长