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

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
测试点编号NM
160
21005
320009
4500000
5500000
6500001
7500006
810000010
910000013
1010000015

保证答案不超过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了,慌得一批,还是好好学习吧,在还没有成为定局之前就是应该一直拼搏

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个参选手有相同的机会和条件进行竞争。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值