大假期集训模拟赛十

T1 字符串的距离(签到题)

题目大意

*设有字符串 X,我们称在 X 的头尾及中间插入任意多个空格后构成的新字符串为 X 的扩展串,如字符串 X为“abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□” 和 “abcb□cd□” 都是 X 的扩展串,这里“ □ ”代表空格字符。

  • 如果 A1 是字符串 A 的扩展串,B1 是字符串 B 的扩展串,A1 与 B1 具有相同的长度,那么我们定义字符串 A1 与 B1 的距离为相应位置上的字符的距离总和:两个非空格字符的距离定义为它们的 ASCII 码的差的绝对值 空格字符与其它任意字符之间的距离为已知的定值 K,
    空格字符与空格字符的距离为 0 。
  • 在字符串 A,B 的所有扩展串中,必定存在两个等长的扩展串 A1,B1,使得 A1 与 B1 之间的距离达到最小,我们将这一距离定义为字符串 A,B的距离。
  • 请你写一个程序,求出字符串 A,B的距离

算法分析:

  • dp呗 很显然就看出来了 考试的时候dp初始化没全 改了就A了

Code



#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e3+10;
char s1[maxn];
char s2[maxn];
int dp[maxn][maxn];//已经匹配好s1的前i位和s2的前j位
int k;

int main(){
	scanf("%s%s%d",s1+1,s2+1,&k);
	memset(dp,0x3f,sizeof(dp));
	int len1 = strlen(s1+1);
	int len2 = strlen(s2+1);
	dp[0][0] = 0;
	for(int i = 1;i <= len1;++i)dp[i][0] = k*i;
	for(int i = 1;i <= len2;++i)dp[0][i] = k*i;
	for(int i = 1;i <= len1;++i){
		for(int j = 1;j <= len2;++j){
			dp[i][j] = min(dp[i-1][j-1] + abs(s1[i] - s2[j]),min(dp[i][j-1] + k,dp[i-1][j] + k));
		}
	}
	printf("%d\n",dp[len1][len2]);
	return 0;
}

T2 Blue Mary的战役地图 (暴力你就赢了)

题目大意

  • BlueMary 最近迷上了玩 Starcraft (星际争霸) 的 RPG
    游戏。她正在设法寻找更多的战役地图以进一步提高自己的水平。
  • 由于 BlueMary的技术已经达到了一定的高度,因此,对于用同一种打法能够通过的战役地图,她只需要玩一张,她就能了解这一类战役的打法,然后她就没有兴趣再玩儿这一类地图了。而网上流传的地图有很多都是属于同一种打法,因此 BlueMary
    需要你写一个程序,来帮助她判断哪些地图是属于同一类的。
  • 具体来说,BlueMary已经将战役地图编码为 n×n 的矩阵,矩阵的每个格子里面是一个 32 位(有符号)正整数。对于两个矩阵,他们的相似程度定义为他们的最大公共正方形矩阵的边长。两个矩阵的相似程度越大,这两张战役地图就越有可能是属于同一类的。

输入格式

  • 输入文件的第一行包含一个正整数 n。
  • 以下 n 行,每行包含 n 个正整数,表示第一张战役地图的代表矩阵。
  • 再以下 n 行,每行包含 n 个正整数,表示第二张战役地图的代表矩阵。

输出格式

  • 输出文件仅包含一行。这一行仅有一个正整数,表示这两个矩阵的相似程度。

算法分析

  • 首先讲第一种做法 暴力直接O(\(n^5\))亲测AC
  • 哈希做法
  • 有点容斥的玩意 首先预处理出来每个节点对应的哈希值 这个哈希表示的是 以这个节点作为矩形右下角的哈希值
  • 然后想要知道任意一个部分的哈希值用最简单的容斥就可以做了(别说不会…………
  • 然后就没啥东西了

Code



#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int base = 11;
const int Base = 13;
const int maxn = 150;
ull a[maxn][maxn],b[maxn][maxn];
int n;
ull rowpw[maxn],colpw[maxn];

ull calc(int flag,int x,int y,int h){//二维hash标准姿势
	if(flag)return b[x][y] - b[x-h][y] * colpw[h] - b[x][y-h] * rowpw[h] + b[x-h][y-h] * rowpw[h] * colpw[h];
	return a[x][y] - a[x-h][y] * colpw[h] - a[x][y-h] * rowpw[h] + a[x-h][y-h]*rowpw[h]*colpw[h];
}

void Solve(){
	for(int i = 1;i <= n;++i)
		for(int j = 1;j <= n;++j)
			a[i][j] = a[i][j-1]*base + a[i][j];//先把一行转成hash
	for(int i = 1;i <= n;++i)
		for(int j = 1;j <= n;++j)
			a[i][j] = a[i-1][j]*Base + a[i][j];//再把一列转成hash  这样一个点就能代表一个矩阵了
	map<ull,bool> mp;
	for(int h = 0;h <= n;++h)
		for(int i = h;i <= n;++i)
			for(int j = h;j <= n;++j)
				mp[calc(0,i,j,h)] = 1;
	for(int i = 1;i <= n;++i)
		for(int j = 1;j <= n;++j)
			b[i][j] = b[i][j-1]*base + b[i][j];
	for(int i = 1;i <= n;++i)
		for(int j = 1;j <= n;++j)
			b[i][j] = b[i-1][j]*Base + b[i][j];
	for(int h = n;h >= 0;--h)
		for(int i = h;i <= n;++i)
			for(int j = h;j <= n;++j)
				if(mp.find(calc(1,i,j,h)) != mp.end()){
					printf("%d\n",h);
					return;
				}
	return;
}

int main(){
	scanf("%d",&n);
	for(int i = 1;i <= n;++i){
		for(int j = 1;j <= n;++j){
			scanf("%llu",&a[i][j]);
		}
	}
	for(int i = 1;i <= n;++i){
		for(int j = 1;j <= n;++j){
			scanf("%llu",&b[i][j]);
		}
	}
	rowpw[0] = colpw[0] = 1;
	for(int i = 1;i <= n;++i)
		rowpw[i] = rowpw[i-1] * base;
	for(int i = 1;i <= n;++i)
		colpw[i] = colpw[i-1] * Base;
	Solve();
	return 0;
}
****

T3反质数 (打表大法好)

题目大意

  • 对于任何正整数 x 其约数的个数记作 g(x)。例如 g(1)=1,g(6)=4 。
  • 如果某个正整数 x 满足:对任意的 i(0<i<x) 满足 g(x)>g(i),则称 x为反质数。
  • 例如,整数 1,2,4,6 等都是反质数。
    现在给定一个数 N ,你能求出不超过 N 的最大的反质数么?

输入格式

N

输出格式

答案

样例

输入

1000

输出

840

算法分析

  • 打表啊 刚开始考试就整个打表 大约仨半小时你就A了
  • 挺高级的玩意 推式子
  • 首先一合数肯定可以分成几个质数相乘的形式(唯一分解定理) ,质数的质因子为2就不用解释了叭(细节叭)
  • 然后看这样一个数756 = \(2^2\) * \(2^3\) * \(7^1\),约数有24个 即三个指数+1 连乘(唯一分解定理
  • 而对于这样一个数756 我们完全可以将7换成一个更小的质数5 然后就有540 = \(2^2\) * \(2^3\) * \(5^1\)
  • 而540的约数数 与 756的一样 所以我们选择540更优
  • 由此我们可以推出来 一个数必须要由连续的几个质数的乘积组成而不能跳数(like 上面那个5与7)
  • 通过这个dfs就好了

Code



#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=1e7+10;
const int pri[]={0,2,3,5,7,11,13,17,19,23,29};

int ans,Mx,n;

void dfs(int x,int d,int idx,int c){
	if(d > Mx || (d == Mx && x < ans))Mx = d,ans = x;
	for(int j = 1;j <= c;++j){
		if(n < (long long)pri[idx] * x)return;
		x *= pri[idx];
		dfs(x,d * (j + 1),idx + 1,j);
	}
}

int main(){
	scanf("%d",&n);
	dfs(1,1,1,31);
	printf("%d\n",ans);
}

T4 sam-Toy Cars(瞎搞就A了)

题目大意

  • Jasio 是一个三岁的小男孩,他最喜欢玩玩具了,他有 n 个不同的玩具,它们都被放在了很高的架子上,所以Jasio 拿不到它们。为了让他的房间有足够的空间,在任何时刻地板上都不会有超过 k 个玩具(Jasio在地板上玩玩具)。
  • Jasio的妈妈则在房间里陪他的儿子。当 Jasio 想玩地板上的其他玩具时,他会自己去拿。如果他想玩的玩具在架子上,他的妈妈则会帮他去拿。当她拿玩具的时候,顺便也会将一个地板上的玩具放上架子使得地板上有足够的空间。他的妈妈很清楚自己的孩子,所以他能够预料到 Jasio 想玩些什么玩具。所以她想尽量的使自己去架子上拿玩具的次数尽量的少,应该怎么安排放玩具的顺序呢?

输入格式

  • 第一行三个整数:n,k,p(1<=k<=n<=105,1<=p<=5×105),分别表示玩具的总数、地板上玩具的最多个数以及 Jasio 他想玩玩具的序列的个数。
  • 接下来 p 行每行描述一个玩具编号,表示 Jasio 想玩的玩具。

输出格式

  • 一个数表示 Jasio 的妈妈最少要拿多少次玩具。

算法分析

  • 贪心的思想 显然如果当前地上已经有了k个玩具 再拿玩具的时候就要放回去一个
  • 而放回去哪个呢? 如果这小p孩下个就要玩A 结果你这次拿了个B把A换了 下次再拿个A 这不是闲的egg疼吗……
  • 所以咱们预处理整他呗 看看这个玩意下次啥时候玩 在现在地板上找一个下次玩的时间最晚的 给它扔了 就好了
  • 这玩意优先队列一搞不就出来了嘛

Code



#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int pos[maxn];
int next[maxn];
int ans;
int vis[maxn];

struct node{
	int val,next;
	node(){
		next = 0x3f3f3f3f;
		val = 0;
	}
	node(int X,int Y){
		next = Y;
		val = X;
	}
	bool operator <(const node &x)const{
		return next < x.next;
	}
}a[maxn];

priority_queue<node> q;

int main(){
	//freopen("in","r",stdin);
	int n,k,m;scanf("%d%d%d",&n,&k,&m);
	for(int i = 1;i <= m;++i)scanf("%d",&a[i].val);
	for(int i = m;i;--i){
		if(pos[a[i].val])a[i].next = pos[a[i].val];
		pos[a[i].val] = i;
	}
	for(int i = 1;i <= m;++i){
		if(!vis[a[i].val]){
			if(ans >= k){
				int now = q.top().val;
				vis[now] = 0;
				q.pop();
			}
			ans++;
			vis[a[i].val] = 1;
		}
		q.push(node(a[i].val,a[i].next));
	}
	printf("%d\n",ans);
	return 0;
}

posted @ 2020-07-30 19:35  HISKrrr  阅读(179)  评论(0编辑  收藏  举报