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();
}