欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【NOIP模拟赛】小奇颓废赛 Day2

程序员文章站 2024-03-20 13:47:28
...

D2T1

小奇挖矿2

【题目背景】
小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎。
 【问题描述】
现在有m+1个星球,从左到右标号为0到m,小奇最初在0号星球。
有n处矿体,第i处矿体有ai单位原矿,在第bi个星球上。
由于飞船使用的是老式的跳跃引擎,每次它只能从第x号星球移动到第x+4号星球或x+7号星球。每到一个星球,小奇会采走该星球上所有的原矿,求小奇能采到的最大原矿数量。
注意,小奇不必最终到达m号星球。

输入
第一行2个整数n,m。
接下来n行,每行2个整数ai,bi。

输出
输出一行一个整数,表示要求的结果。

样例输入
3 13
100 4
10 7
1 11

样例输出 Copy
101

提示
【样例解释】
第一次从0到4,第二次从4到11,总共采到101单位原矿。
 
【数据范围】
对于20%的数据 n=1,m<=10^5
对于40%的数据 n<=15,m<=10^5
对于60%的数据 m<=10^5
对于100%的数据 n<=10^5,m<=10^9,1<=ai<=10^4,1<=bi<=m

初眼思路:搜索。。。

打出来之后不敢交,最后水了二十分

正解:线性动态规划

  • 因为我们只能走4步或者7步,根据小凯的疑惑定理,易知4*7-4-7=18之后的步数我们都可以到达,于是我们可以先根据距离排序,然后把两点之间大于17的点之间设为18

  • 然后我们只需要从头开始进行动态规划就可以了,可是为什么要这样进行动态规划呢

  • 我们只能走4或者7步,不走一定不是最优解,所以我们考虑走4步或者走7步,当前走4步也许比走7步要优,但是走7步在后面也许是最优解,这是我们怎样理解这个转移方程呢

  • 因为我们在后面仍然可以更新,最终我们当前走的这4步,后面走7步的最优解会更新出来,所以确保了我们转移方程的正确性

核心代码

for(int i=1;i<=n;i++) {
        if(e[i].b-e[i-1].b>17) now+=18,v[now]+=e[i].a;
        else now+=e[i].b-e[i-1].b,v[now]+=e[i].a;
    }
    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[i]);
        }
    }

D2T2

小奇的矩阵

【题目背景】
小奇总是在数学课上思考奇怪的问题。
 【问题描述】
给定一个n*m的矩阵,矩阵中的每个元素aij为正整数。
接下来规定
1.合法的路径初始从矩阵左上角出发,每次只能向右或向下走,终点为右下角。
2.路径经过的n+m-1个格子中的元素为A1,A2…A(n+m-1),Aavg为Ai的平均数,路径的V值为(n+m-1)*∑(Ai-Aavg) ^2
(1<=i<=n+m-1)
求V值最小的合法路径,输出V值即可,有多组测试数据。

输入
第一行包含一个正整数T,表示数据组数。
对于每组数据:
第一行包含两个正整数n和m,表示矩阵的行数和列数。
接下来n行,每行m个正整数aij,描述这个矩阵。

输出
对于每次询问,输出一行一个整数表示要求的结果

样例输入
1
2 2
1 2
3 4

样例输出
14

提示
对于30%的数据 n<=10,m<=10
有另外40%的数据 n<=15 m<=15,矩阵中的元素不大于5
对于100%的数据 T<=5,n<=30,m<=30,矩阵中的元素不大于30

初眼思路:多维动态规划

但是题目中给的n+m-1我不知道是乘在里面还是乘在外面,我把每种情况都试了,没有一个对住样例的,于是我就放弃了,怪我咯

正解:多维动态规划

  • 我们首先把题目中所给的式子变形Ans=(n+m−1)(A12+A22+…+An+m−12)−2Sum2+Sum2=(n+m−1)(A12+A22+…+An+m−12)−Sum^2
    转载于此地

  • 我们定义一个三维数组f[i][j][k]来记录当前坐标记录的总和值为k的最小值(我也是第一次遇到这样的动态规划题,涨知识了)

核心代码

f[1][1][map[1][1]]=map[1][1]*map[1][1];
for(int i=1;i<=n;i++) {
	for(int j=1;j<=m;j++) {
		if(i==1&&j==1) continue;
		for(int k=map[i][j];k<=1770;k++) {
			f[i][j][k]=min(f[i-1][j][k-map[i][j]],f[i][j-1][k-map[i][j]])+map[i][j]*map[i][j];
		}
	}
}
ans=1e9;
for(int k=0;k<=1770;k++) {
	tot=1ll*(n+m-1)*f[n][m][k]-k*k;
	if(ans>tot) ans=tot;
}

D2T3

小奇的仓库

【题目背景】
小奇采的矿实在太多了,它准备在喵星系建个矿石仓库。令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 
【问题描述】
喵星系有n个星球,星球以及星球间的航线形成一棵树。
从星球a到星球b要花费[dis(a,b) Xor M]秒。(dis(a,b)表示ab间的航线长度,Xor为位运算中的异或)
为了给仓库选址,小奇想知道,星球i(1<=i<=n)到其它所有星球花费的时间之和。

输入
第一行包含两个正整数n,M。
接下来n-1行,每行3个正整数a,b,c,表示a,b之间的航线长度为c。

输出
n行,每行一个整数,表示星球i到其它所有星球花费的时间之和。

样例输入
4 0
1 2 1
1 3 2
1 4 3

样例输出
6
8
10
12
测试点编号 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

保证答案不超过2*10^9

初眼思路:倍增

类似于同时处理f和dis数组,但是我打了两个多小时,在自己造的数据中还是挂了,最后想打个树的遍历,没时间了,于是成功爆0

正解:树形动态规划

据说是两遍dfs就可以了,大佬说是换根DP,我也听不懂,最终在百思不得其解之后放弃


摘自大佬题解

首先考虑不异或

那么我们先算出根节点1到所有点的距离和

接下来假设2是1儿子,边为<1,2,w>,size[i]为i的子树的大小

ans[2]=ans[1]+(n-size)w-sizew=ans[1]+(n-2*size)*w

但本题加了异或,异或不满足分配律,所以不能算出再异或

但我们发现m很小,最多也就2^4-1,也就是1111

异或只会影响后4位

于是设f[i][j]为i到其它点,后4位状态为j的路径条数

显然列出:

f[u][0]=1

f[u][(j+w)%16]+=f[v][j]

这还只算了子树

f[v][(j+w)%16]+=(f[u][j]-f[v][((j-w)%16+16)%16])

解释一下,u这个点的所有f[u][j]除去v的方案再加入v,等于把v的方案

从子树补到整棵

AC代码

#include<cstdio>
#define N 100005
using namespace std;
struct edge {
	int next,to,l;
}e[N<<1];
int n,m,cnt,head[N],f[N],g[N],sz[N],up[N][16];
inline void add(int x,int y,int z) {
	e[++cnt].to=y,e[cnt].l=z,e[cnt].next=head[x],head[x]=cnt;
}
inline void dfs1(int x,int fa) {
	sz[x]=1;
	for(int i=head[x];i;i=e[i].next) {
		int y=e[i].to,l=e[i].l;
		if(y==fa) continue;
		dfs1(y,x);
		g[x]+=g[y]+l*sz[y];
		sz[x]+=sz[y];
		for(int j=0;j<16;j++) {
			int k=j+l;k-=k>>4<<4;
			up[x][k]+=up[y][j];
		}
		up[x][l-(l>>4<<4)]++;
	}
}
inline void dfs2(int x,int fa,int cnt) {
	g[x]+=f[x]; int sum=g[x];
	int s=cnt+sz[x],d[20];
	for(int i=head[x];i;i=e[i].next) {
		int y=e[i].to,l=e[i].l;
		if(y==fa) continue;
		f[y]=sum-g[y]+l*(s-sz[y]*2);
		for(int i=0;i<16;i++) d[i]=up[x][i];
		for(int j=0;j<16;j++) {
			int k=j+l;k-=k>>4<<4;
			d[k]-=up[y][j];
		}
		d[l-(l>>4<<4)]--;
		for(int j=0;j<16;j++) {
			int k=j+l;k-=k>>4<<4;
			up[y][k]+=d[j];
		}
		up[y][l-(l>>4<<4)]++;
		dfs2(y,x,s-sz[y]);
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++) {
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z),add(y,x,z);
	}
	dfs1(1,0);
	dfs2(1,0,0);
	for(int i=1;i<=n;i++) {
		for(int j=0;j<16;j++) {
			int k=j^m;
			g[i]+=(k-j)*up[i][j];
		}
		printf("%d\n",g[i]);
	}
	return 0;
}

最终得分20+0+0=20,还有四十天就要2019CSP了,慌得一批,还是好好学习吧,在还没有成为定局之前就是应该一直拼搏

相关标签: NOIP模拟赛