首页 > 其他分享 >2018年安徽省赛小学组题解

2018年安徽省赛小学组题解

时间:2024-08-23 22:15:06浏览次数:6  
标签:卡卡 积木 int 题解 long times 安徽省 2018 dp

T1:移动石子(stone)

题目描述

期待已久的“清明”假期终于到了。清明节是中华民族几千年来留下的优良传统,它有利于弘扬孝道亲情,唤醒家庭共同记忆,促进家庭成员乃至民族的凝聚力和认同感。

小学生卡卡西非常高兴,因为清明前后正是踏青的好时光,他终于可以和小伙伴们一起出去踏青了!然而,天公不作美,假期的第一天就下起了雨,卡卡西只能放弃出游计划,待在家里。

期间,无聊的卡卡西和小伙伴玩了一个博弈游戏:

\(n\times n\) 棋盘左上角放置了一块石头,两人轮流移动此石头,每次操作只能上下左右四个方向移动一格位置,并且已经走过的格子不能再次重复移动,若卡卡西先移动,且两人都用最优的策略移动,谁能赢?谁先不能移动了为输,其中:\(1≤n≤10000\)。

输入格式

多行数据,以最后一行为 \(0\) 时结束,每一行表示一个数表示 \(n\)。

输出格式

多行数据,每行对应一个输出结果,若卡卡西能赢则输出 Kakashi,否则输出 Lost

样例

输入#1

2
0

输出#1

Kakashi

数据范围

对于 \(20\%\) 的数据,保证 \(1≤n≤10\);
对于 \(40\%\) 的数据,保证 \(1≤n≤1000\);
对于 \(100\%\) 的数据,保证 \(1≤n≤10000\)。


思路分析

想象一下,可以把整个棋盘拆成若干个 \(1\times 2\) 的格子,卡卡西先走,那么:

  • 很明显,先手的卡卡西只是从一个小格子的一侧走到了另一侧;
  • 而后手则需要找到一个新的 \(1\times 2\) 的格子。

因此,如果棋盘能被完整拆分成 \(1\times 2\) 的格子,那么一定是后手先找不到格子,然后输掉。

当 \(n\times n\) 为奇数时,总格子数为奇数,无法拆分,卡卡西必输。

当 \(n\times n\) 为偶数时,棋盘能完整拆分成 \(1\times 2\) 的格子,此时卡卡西必赢,必赢的策略就如上面分析的:只要保证剩下的可以走的格子数量一定是偶数,就可以保证他自己必赢。

注意多组测试数据。

\(\texttt{code}\)

/*Written by smx*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define QAQ cout<<"QAQ";
const int MAXN=1e5+5,inf=1e18,mod=1e9+7;

signed main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n;
	while(cin>>n&&n!=0){
		if(n%2==0){
			cout<<"Kakashi\n";
		}else{
			cout<<"Lost\n";
		}
	}
	return 0;
}

T2:列车路线(train)

题目描述

终于,卡卡西来到了一个叫“比特兰”的国家,“比特兰”是个很发达的国家,有着非常高科技的列车,和非常复杂的列车线路。具体来说,从理论上,我们可以假设这个国家的高科技列车可以不消耗时间的从 \(A\) 地瞬间转移到 \(B\) 地。同时,铁路线路复杂到,每对城市之间都有列车连接。但是不幸的是,由于这种列车运行需要很多维护工作,所以每天只能发出一次。从 \(i\) 到 \(j\) 的列车(\(i \neq j\))会在 \(t_{ij}\) 时间发出(保证 \(t_{ij}\) 两两不同)。

如果有一条路径连接 \(A\) 和 \(B\) 两个城市,并且满足路径上的每一条边的发车时间单调递增(也就是说经过的每段铁路的发出时间都要大于上一段的,因为我们需要从上一段铁路换乘下一段铁路),那么就是一条可行的从 \(A\) 到 \(B\) 的路线。 现在“比特兰”的铁路局想要知道,一天之内,对于每一对 \(i\) 和 \(j\),如果想要从 \(i\) 到达 \(j\),最早多早能到达呢?

输入格式

第 \(1\)行是一个整数 \(n\),接下来 \(n\) 行,每行 \(n\) 个数表示 \(t_{ij}(i=j,t_{ij}=0)\)。

输出格式

\(n\)行,每行 \(n\) 个数表示 \(i\) 到 \(j\) 最早的到达时间。

样例

输入#1

3
0 4 5
2 0 3
1 6 0

输出#1

0 4 5
2 0 3
1 4 0

数据范围

对于 \(20\%\) 的数据,\(n≤10\)
对于 \(40\%\) 的数据,\(n≤20\)
对于 \(60\%\) 的数据,\(n≤50\)
对于 \(100\%\) 的数据,\(n≤500, t_{ij}≤10^9\)


思路分析

我们先看数据范围,\(n\leq 500\),很明显这个数据范围我们第一个想到的就是时间复杂度为 \(O(n^3)\) 的 Floyd,我们不难想到求全源最短路的 Floyd 算法,可是 WA 了/fn/fn/fn,原因是 Floyd 的思路是枚举每一个中间点去更新每两点之间的距离,必须满足具备最优子结构,可这道题不满足,因此我们无法使用 Floyd。

我们再想想,最短路还可以使用 dijkstra 算法,dijkstra 适用于单源最短路,它的的思路大致是每次选择一个最短路径长度已经确定的结点,然后通过从这个结点出发的边,更新其余还未完全确定最短路径长度的结点。这样反复确定 \(n\) 次,就确定了所有结点的最短路。对于这道题,我们将 dijkstra 的模板稍作修改即可。

我们知道,朴素版 dijkstra 求单源最短路的时间复杂度是 \(O(n^2)\),而利用堆优化的 dijkstra 这道题求单源最短路的时间复杂度是 \(O(m\log m)\),这里 \(m\) 表示边的数量。在这道题 \(m=n^2\) ,是稠密图,时间复杂度还不如朴素版。

由于这道题求的是全源,我们需要调用 \(n\) 次,每次的源点是 \(i\) ,所以最终的时间复杂度是 \(\Theta(n^3)\),可以通过此题。

\(\large \texttt{AC code}\)

/*Written by smx*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define QAQ cout<<"QAQ";
const int MAXN=505,inf=1e18,mod=1e9+7;
int n;
int g[MAXN][MAXN];
int dist[MAXN][MAXN];
int vis[MAXN];
void dijkstra(int s){
	memset(vis,0,sizeof(vis));
	dist[s][s]=0;
	for(int i=1;i<=n;i++){
		int minn=-1,pos=2e9;
		for(int j=1;j<=n;j++){
			if(!vis[j]&&dist[s][j]<pos){
				minn=j;
				pos=dist[s][j];
			}
		}
		vis[minn]=1;
		for(int j=1;j<=n;j++){
			if(dist[s][minn]<g[minn][j]){
				if(dist[s][j]>g[minn][j]){
					dist[s][j]=g[minn][j];
				}                
			}
		}
	}
}
signed main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>g[i][j];
		}
	}
	memset(dist,0x7f,sizeof(dist));
	for(int i=1;i<=n;i++){
		dijkstra(i);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<dist[i][j]<<" ";
		}
		cout<<"\n";
	}
	return 0;
}

T3:搭积木(block)

题目描述

积木对于大家来说应该很熟悉,我们可以用积木搭建出各种各样的模型,不同的人搭建出来的模型也会不一样。这不,小卡卡西正在和一群小伙伴玩积木呢!

铁人老师看见小朋友们在玩积木,就给大家出了一个难题:

积木的三边的边长是 \(X、Y、Z\), 每类积木可以有无限多个,搭积木时规定:每层只能放一个积木;上层积木的底部面积(积木的每个面都可以作为底面)必须小于其下层(上层积木的两条边必须严格小于下层积木)。

如何搭建能搭得最高。

输入格式

第一行\(n\)表示积木种类数量,接下来 \(n\) 行,每行三个整数 \(X、Y、Z\)。

输出格式

最大高度。

样例

输入#1

1
10 20 30

输出#1

40

输入#2

4
1 6 1
10 1 1
2 6 10
1 2 3

输出#2

22

数据范围

\(n\leq 1000\)
\(X,Y,Z\leq 100\)


本题有多种解法。

思路分析

解法一:LIS

从“上层积木的底部面积(积木的每个面都可以作为底面)必须小于其下层(上层积木的两条边必须严格小于下层积木)”,不难看出这是一道 LIS(最长上升子序列)的 dp。

我们套一个 LIS 的板子,由于题目中没有规定积木摆放的方向,所以我们可以记录每块积木能摆成的三种方向,排一下序套 LIS 板子即可。

\(\texttt{code}\)

/*Written by smx*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define QAQ cout<<"QAQ";
const int MAXN=3e3+5,inf=1e18,mod=1e9+7;
int n,t;
struct hjmfdg{
	int x,y,z;
}a[MAXN];
int f[MAXN];
bool cmp(hjmfdg a,hjmfdg b){
	if(a.x!=b.x){
		return a.x<b.x;
	}
	return a.y<b.y;
}
signed main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		int x,y,z;
		cin>>x>>y>>z;
		if(x>y)swap(x,y);
		if(y>z)swap(y,z);
		if(x>y)swap(x,y);
		a[++t]={x,y,z};
		a[++t]={x,z,y};
		a[++t]={y,z,x};
	}
	sort(a+1,a+t+1,cmp);
	int ans=0;
	for(int i=1;i<=t;i++){
		f[i]=a[i].z;
		for(int j=1;j<i;j++){
			if(a[j].x<a[i].x&&a[j].y<a[i].y){
				f[i]=max(f[i],f[j]+a[i].z);
			}
		}
		ans=max(ans,f[i]);
	}
	cout<<ans;
	return 0;
}

时间复杂度 \(O(n^2)\)。


解法二:记忆化搜索

还是 dp,我们定义 \(dp_{i,j}\) 表示在 \(i\times j\) 的区域大小内搭出的最大高度。

因为一层只能放一块积木,所以我们每次记忆化搜索只需要找出搭上这块积木的答案的最大值即可,这块积木的答案即以这块积木为底的答案加上这块积木的高,即:

\[dp_{i,j}=\max(dp_{i,j},dfs(x_i,y_i)+z_i) \]

如此一来,进行记忆化搜索,即可求得最终答案。记忆化搜索,相比于普通 dfs,用 \(dp_{i,j}\) 记录答案,避免多次求答案,直接使用记录的答案即可,时间复杂度便有了巨大的提升。

还是要记录每块积木能摆成的三种方向。

\(\texttt{code}\)

/*Written by smx*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define QAQ cout<<"QAQ";
const int MAXN=3e3+5,inf=1e18,mod=1e9+7;
int n;
int a[MAXN],b[MAXN],c[MAXN],dp[MAXN][MAXN];
int dfs(int x,int y){
	if(dp[x][y]!=-1){
		return dp[x][y];
	}
	dp[x][y]=0;
	for(int i=1;i<=n;i++){
		if(a[i]<x&&b[i]<y){
			dp[x][y]=max(dp[x][y],c[i]+dfs(a[i],b[i]));
		}
	}
	return dp[x][y];
}
signed main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	int t=0;
	for(int i=1;i<=n;i++){
		int x,y,z;
		cin>>x>>y>>z;
		a[++t]=x;b[t]=y;c[t]=z;if(a[t]>b[t]) swap(a[t],b[t]);
		a[++t]=x;b[t]=z;c[t]=y;if(a[t]>b[t]) swap(a[t],b[t]);
		a[++t]=y;b[t]=z;c[t]=x;if(a[t]>b[t]) swap(a[t],b[t]);
	}
	n=t;
	memset(dp,-1,sizeof(dp));
	cout<<dfs(101,101);
	return 0;
}

标签:卡卡,积木,int,题解,long,times,安徽省,2018,dp
From: https://www.cnblogs.com/shimingxin1007/p/18377166

相关文章

  • CF1514D Cut and Stick 题解
    题目传送门前置知识可持久化线段树解法若区间内不存在绝对众数,直接保持这一段即可。若存在绝对众数,贪心地想肯定要尽可能地把其分开还要限制出其他数使其不成为绝对众数。容易发现设绝对众数出现次数为\(cnt\),取\(cnt-1\)个其他数和绝对众数配对最优。但可能其他数不够\(......
  • 题解:P10906 [蓝桥杯 2024 国 B] 合法密码
    本来以为字符串多大,结果就这点,直接暴力。枚举起始点,对于每个起始点枚举后面\(8\sim16\)位有没有能用的即可。最后答案为\(400\)。附:计算代码枚举代码如下:for(inti=0;i<n;++i){for(intlength=8;length<=16;++length){if(i......
  • 题解:P10903 [蓝桥杯 2024 省 C] 商品库存管理
    题目大意有一个初始化为\(0\)的长度为\(n\)的序列,现有\(m\)个操作,每次将区间\([L,R]\)中的数量加\(1\),求如果不做某个操作将会有多少个数量为\(0\)的量。解题思路当看见这句话时就想到了差分,这题我们可以使用差分先处理将所有的操作执行后的数组,然后在算出如果减......
  • P10404 「XSOI-R1」原神数 题解
    一篇题解需要一张头图。容易发现超过十位的数都不是原神数,因为只有十个数字,不可能保证十一个位置互不相同。同时恰好十位的数也不可能是原神数,因为数位互不相同的十位数的数位和为\(45\),被\(3\)整除,一定是\(3\)的倍数。于是把原神数的范围缩小到\([1,10^9)\)。显然不......
  • P10528 [XJTUPC2024] 崩坏:星穹铁道 题解
    求方案数,分多种情况,不难想到DP。设\(dp_{i,j}\)表示已经行动\(i\)次,剩余战技点个数为\(j\)的方案数,容易得到以下转移方程。\(a_i=1\)时,有\[dp_{i,j}=\begin{cases}0,&j=0,\\dp_{i-1,j-1},&1\leqslantj\leqslant4,\\dp_{i-1,j-1}+dp_{i......
  • LGP10702 [SNCPC2024] 下棋题解
    P10702[SNCPC2024]下棋本蒟蒻的第一篇题解定位博弈论(nim)+进制转换相关知识OIWIKI博弈论NIM进制转换正题读题所有k进制下所有数位的乘积为自身因子的数。他称之为LNC数。给出x枚棋子,然后LNC选定一个整数k(k≥2)。随后他们交替取走若干枚棋子,要求取走的棋......
  • 【题解】Solution Set - NOIP2024集训Day14 CDQ分治
    【题解】SolutionSet-NOIP2024集训Day14CDQ分治https://www.becoder.com.cn/contest/5482「CF364E」EmptyRectangles*3000摆烂了。「SDOI2011」拦截导弹CDQ的例题,之前做过(现在试图自己再做出来。第二问只用在第一问里面记录每一次是从哪个\(j\)​转移过来的,以及......
  • P10559 [ICPC2024 Xi'an I] The Last Cumulonimbus Cloud 题解
    这种题有一个常见的根号分治做法:设\(d\)为度数,显然有\(O(1)\)修改单点,\(O(d)\)查询邻域和\(O(d)\)修改邻域,\(O(1)\)查询单点两种暴力。对度数大于\(\sqrtn\)的点使用前者,度数小于等于\(\sqrtn\)的点使用后者,可以做到\(O(m\sqrtn)\)的时间复杂度。这种做法的本......
  • CF1575G GCD Festival 题解
    考虑欧拉反演\[\sum\limits_{d\midn}\varphi(d)=n\]则原式可以化为\[\begin{align*}&\sum\limits_{i=1}^n\sum\limits_{j=1}^n\gcd(a_i,a_j)\cdot\gcd(i,j)\\=&\sum\limits_{i=1}^n\sum\limits_{j=1}^n\gcd(a_i,a_j)\sum\li......
  • CF163E e-Government 题解
    题目传送门前置知识AC自动机|树状数组解法一次性将所有模式串加入AC自动机,然后处理加入和删除,考虑单次操作对答案的贡献。因为模式串\(T\)在文本串\(S\)中出现的次数之和等价于\(T\)在\(S\)的所有前缀中作为后缀出现的次数之和。这就很和\(fail\)树上跳到根节......