CCPC-Wannafly Camp Day1总结

CCPC-Wannafly Camp Day1总结

1.报到

在自己学校参加的camp,体验一般吧。不过报到流程挺简便。快过年了,没啥吃的有点难受。

2.训练赛

7-2 1B. 密码学

考虑一种加密方式,它需要一个任意长度的原文 m 和秘钥 key,其中要求原文和秘钥只包含大写和小写的英文字符。

首先定义字符之间的加密,用字符 a 去加密字符 b 的结果是:

首先把 a 和 b 转成数字 x 和 y。转换的规则是,小写字母 a 到 z 依次对应 0 到 25,大写字母依次对应 26 到 51。

计算 x 和 y 的和 z,对 52 取模,即计算 (x+y) mod 52。

返回数字 z 对应的字符。

现在来讲如何用秘钥 key 来加密原文 m:

如果秘钥的 key 的长度小于 m,那么不停重复 key 直到长度不小于 m 为止。举例来说,如果原文是 beijing,秘钥是 PKUSAA,那么秘钥需要被重复称 PKUSAAPKUSAA。

假设原文的长度是 n,那么对于每一个 [1,n] 的数字 i,都用 key 的第 i 个字符去加密 m 的第 i 个字符。

返回结果。

那么用 PKUSAA 去加密 beijing 的结果就是:QOcbINV。

现在火山哥有 n 个字符串,s
​1
​​ 到 s
​n
​​ ,他对这些字符串做了 m 次加密操作:第 i 次加密操作用第 s
​x
​i
​​
​​ 去加密 s
​y
​i
​​
​​ ,并把 s
​y
​i
​​
​​ 替换成加密结果。

现在依次给出 m 次加密操作,以及加密操作结束后每一个字符串的模样,你可以还原出这 n 个字符串原来的模样吗?

输入格式:
第一行输入两个整数 n,m(1≤n,m≤1000)。

接下来 m 行每行输入两个整数 x
​i
​​ ,y
​i
​​ ,表示依次加密操作,保证 x
​i
​​ 不等于 y
​i
​​ 。

接下来 n 行每行输入一个字符串,表示加密最后的结果。字符串的长度在 1 到 100 之间,只包含大小写英文字符。

输出格式
输出 n 行,每行一个字符串,表示原本的字符串。

输入样例:
2 1
1 2
PKUSAA
QOcbINV

输出样例:
PKUSAA
beijing

作者: 2020,Winter,Day1
单位: 东北大学秦皇岛分校
时间限制: 1000 ms
内存限制: 256 MB

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
int main()
{
	int n,m;
	cin>>n>>m;
	string s[1005];
	int c[1005][5];
	for(int i=1; i<=m; i++)
	{
		cin>>c[i][1]>>c[i][2];
	}
	for(int i=1; i<=n; i++) cin>>s[i];
	for(int i=m; i>=1; i--)
	{
		for(int j=0; j<s[c[i][2]].size(); j++)
		{
			int lin1=0,lin2=0,lin=0;
			if(s[c[i][2]][j]>='A'&&s[c[i][2]][j]<='Z') lin1=s[c[i][2]][j]-'A'+26;
			else lin1=s[c[i][2]][j]-'a';
			if(s[c[i][1]][j%s[c[i][1]].size()]>='A'&&s[c[i][1]][j%s[c[i][1]].size()]<='Z') lin2=s[c[i][1]][j%s[c[i][1]].size()]-'A'+26;
			else lin2=s[c[i][1]][j%s[c[i][1]].size()]-'a';
			lin=lin1-lin2;
			if(lin<0) lin+=52;
			if(lin<=25)
			{
				s[c[i][2]][j]='a'+lin;
			}
			else 
			{
				s[c[i][2]][j]='A'+lin-26;
			}
		}
	}
	for(int i=1; i<=n; i++) cout<<s[i]<<endl;
	return 0;
}

思路

签到题,但其实是我们做的第二题,另一题想到一半才开始跟榜。队友敲的,主要就是一步步推回去。

7-8 1H. 最大公约数

有三个人,A,B,C,其中 A 和 B 共享了一个神秘的数字 k,已知 1≤k≤n。

现在 A 和 C 说:“k 的值等于 x”。

C 不太信任 A,于是想向 B 确认一下 k 是否真的等于 x。B 虽然不想直接把 k 的值告诉 C,但是 B 允许 C 给出一个正整数 y(注意 y 可以大于 n),然后 B 会回答 gcd(k,y)。

现在给出 k,n,你需要帮助 C 决定这样的 y 的取值,使得 C 一定可以通过 B 的回答来判断 A 有没有撒谎。如果这样的 y 有多个,你需要输出最小的那个。

输入格式:
输入第一行是一个整数 T(1≤T≤50)。

对于每组数据,输入一行两个整数 n,k(1≤k≤n≤500)。

输出格式
对于每组数据,输出一行一个整数,表示答案。如果满足条件的 y 不存在,则输出 −1。

输入样例:
3
10 1
10 4
10 7

输出样例:
210
8
7

#include<iostream>;
#include<cstring>;
using namespace std;
int a[510];
int b[510];
int c[1010];
bool book[1000];
int sushu[800], q=1;
void su()
{
	sushu[0]=1;
	memset(book, 0, sizeof(book));
	for(int i=2; i<1000; i++)
	{
		if(!book[i])
		{
			sushu[q++]=i;
			book[i]=1;
			for(int j=1; j*i<1000; j++)
			{
				book[j*i]=1;
			}
		}
	}
}
void cf(int aa[500],int bb[500]){
	int i,j;
	memset(c,0,sizeof(c));
	for (i=500;i>=0;i--){
		for(j=500;j>=0;j--){
			int x=c[i+j]+aa[i]*bb[j];
			c[i+j]=x%10;
			c[i+j-1]=c[i+j-1]+x/10;
		}
	}

	for(i=0;i<=500;i++) a[i]=c[i+500];
}

int main()
{
	su();
	long long k, n, t;
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
		int ii=500;
		memset(a,0,sizeof(a));
		int kk=k;
		while(kk!=0){
			a[ii]=kk%10;
			kk=kk/10;
			ii=ii-1;
		}
		for(int i=0; i<q; i++)
		{
			if(k*sushu[i]>n)
				break;
			memset(b,0,sizeof(b));
			int temp=sushu[i];
			int jj=500;
			while(temp!=0){
				b[jj]=temp%10;
				temp=temp/10;
				jj--;
			}
			cf(a,b);
			
		}
		int i=0;
		while((i<=1000)&&(c[i]==0)){
			i++;
		}
		for(i;i<=1000;i++) cout<<c[i];
		cout<<endl;
	}
} 

思路

主要思路见程序。要点有:
1.其实是没有-1这种情况的,任何数都可以找到符合题意的解
2.数据量很大,所以要用高精度乘法,不然会爆。

一开始没考虑到数据可能会很大,结果就爆了。之后我在队友的基础上改成了高精度乘法就a了。
第一天打比赛,高精度都写的磕磕绊绊,丢人。

3.补题

预计乘法这题可以补出来。
在考场里还研究了k小数,本来以为就是用线段树模拟题目操作,但发现复杂度是过不了的,需要优化。

7-9 1I. K小数查询

热爱学习刻苦奋斗的九条可怜最近做了很多数据结构题,接触到了 K 小数查询这一系列的问题以及线段树的重磅打击这一套理论,她觉得这两样东西都很厉害,所以想要出一道题。

给出一个长度为 n 的数列 A,接下来有 m 次操作,操作有两种:

1 l r x,表示对 i∈[l,r],令 A
​i
​​ =min(A
​i
​​ ,x)

2 l r k,表示询问区间 [l,r] 中第 k 小的数。

这个问题对可怜来说有点难,你能帮帮她吗。

输入格式:
第一行输入两个整数 n,m(1≤n,m≤8×10
​4
​​ )。

接下来一行 n 个整数描述数组 A(1≤A
​i
​​ ≤n)。

接下来 m 行每行描述一个操作,操作格式与题面中相同,保证 1≤l≤r≤n,1≤k≤r−l+1,1≤x≤10
​9
​​ 。

输出格式
对于每组询问,输出一个整数表示答案。

输入样例:
3 5
1 2 3
2 1 3 2
1 3 3 1
2 1 3 2
1 1 2 3
2 1 3 2

输出样例:
2
1
1

错的思路VS对的

考场上按照线段树写的,裸的搜索和修改。
标答做法为树套树。

7-6 1F. 乘法

给出一个长度为 n 的数列 和一个长度为 m 的数列 ,可以构造得到一个 n×m 的矩阵 C,其中 C
​i,j
​​ =A
​i
​​ ×B
​j
​​ 。

给出整数 K,你需要求出 C 中第 K 大的数的值。

输入格式:
第一行输入三个整数 n,m,K(1≤n,m≤10
​5
​​ ,1≤K≤n×m)。

第二行输入 n 个空格隔开的整数 A
​1
​​ ,…,A
​n
​​ (−10
​6
​​ ≤A
​i
​​ ≤10
​6
​​ )

第三行输入 m 个空格隔开的整数 B
​1
​​ ,…,B
​m
​​ (−10
​6
​​ ≤B
​i
​​ ≤10
​6
​​ )

输出格式
输出一行一个整数,表示矩阵中的第 K 大的数的值。

输入样例:
3 3 3
2 3 4
4 5 6

输出样例:
18

思路

裸的二分

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,m,k;
int a[100010],b[100010];
bool check(long long p){
	long long t=0;
	long long i,j;
	for(i=1;i<=n;i++){
		j=m;
		while((j>=0)&&(a[i]*b[j]>p)){
			j=j-1;
		}
		t=t+j;
	}
	return t>=k;
}
long long solve(){
	long long l,r,mid;
	l=a[1]*b[1];
	r=a[n]*b[m];
	while(l<r){
		mid=(l+r)>>1;
		if(!check(mid)) l=mid+1;
		else r=mid;
	}
	return l;
}

int main(){
	long long i,j;
	cin>>n>>m>>k;
	for(i=1;i<=n;i++){
		cin>>a[i];
	}
	for(i=1;i<=m;i++){
		cin>>b[i];
	}
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	k=n*m-k+1;
	cout<<solve();
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值