牛客周赛 Round 106
现在小苯给定了你 a3 到 an 的所有数字,请你还原出波浪序列对应的第一个和第二个数字 a1 和 a2。解题思路:对于你选择的数字ai, 经过与ai/2 , 按位异或后, 多次执行这个操作后, 会重新变回ai,所以原数字中的前后数对, 如果想成功匹配, 必须是在对方的循环里面的, 然后取最小值。解题思路:通过手动模拟就会发现, 我们在从个位洞数增加的到十位洞数再到百位洞数的过程中只有1 4
A. 小苯的方格覆盖
猪猪王图拨号
最近迷上了华容道游戏,这天他找到了他的部下撤云猪猪
并给了他一个 3 行 n 列的矩阵。
图拨号希望撤云猪猪用一种 1×2 的小方格(可以旋转 90 度,即覆盖两个在同一行或同一列上相邻的格子)恰好填满这个矩阵,不能有空位,小方格之间也不能重叠。
只需要帮撤云猪猪判断是否可以用 1×2 的小方格填满这个 3 行 n 列的矩阵即可。
注意:1×2 的小方格可以旋转 90 度,变成 2×1 的小方格。
解题思路:只要列是偶数的都能用小方格进行填满
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n;
cin>>n;
if(n%2==0) cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
int main() {
int t=1;
// cin >> t;
while (t--) {
solve();
}
return 0;
}
B. 小苯的数字折叠
小苯发现了一种特殊的数字运算,称为“数字折叠”。对于一个正整数 x,定义其折叠操作为:
,∙将 x 的各位数字倒序排列并除去前导 0 得到 x′;
,∙计算 x+x′ 得到新数字;,∙重复这个过程直到得到一个回文数。
例如,对于 x=68,有:
,∙第一次折叠:68+86=154;
,∙第二次折叠:154+451=605;第三次折叠:605+506=1111。
现在给定一个正整数 n 和最大操作次数 k,请判断:n 在最多 k 次折叠操作内(当然,也可以不操作)是否能变成回文数。如果能,输出最少操作次数得到的回文数和最少的操作次数;如果不能,输出第 kkk 次操作后的结果和 −1。
解题思路:模拟
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
bool fun(ll n){
ll sum=n,tmp=0;
while(n>0){
tmp=tmp*10+n%10;
n/=10;
}
if(tmp==sum) return true;
else return false;
}
ll fun_(ll n){
ll tmp=0;
while(n>0){
tmp=tmp*10+n%10;
n/=10;
}
return tmp;
}
void solve() {
ll n,k;
cin>>n>>k;
int f=0;
for(int i=0;i<k;i++){
if(fun(n)){
break;
}else{
f++;
n+=fun_(n);
}
}
if(fun(n)) cout<<n<<" "<<f<<'\n';
else cout<<n<<" "<<-1<<'\n';
}
int main() {
// int t=1;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C. 小苯的波浪加密器
小苯升级了她的数字波浪生成器,现在它变成了一个加密器。给定一个长度为 n−2 的数字序列 a3,a4,…,an 和两个区间 [L1,R1][L2,R2]。
数字波浪序列的生成过程如下:
,∙小苯从 [L1,R1] 区间中选择一个数字作为波浪序列的第一个数字 a1。
小苯从 [L2,R2] 区间中选择一个数字作为波浪序列的第二个数字 a2。
,∙从第三个数字开始,每个数字都等于前面两个数字的乘积的个位数。
现在小苯给定了你 a3 到 an 的所有数字,请你还原出波浪序列对应的第一个和第二个数字 a1 和 a2。如果存在多个解,请输出使得整个波浪序列字典序最小的答案(即优先最小化 a1,其次最小化 a2)。
注意,输入只保证 a5 到 an 满足上述关系;a3、a4 给出但不一定与未知的 a1、a2 一一对应,需求解时自行验证是否存在 a1、a2 使得整个序列一致。如果无解,则输出两个固定的整数 −1。
解题思路:有用的只有个位数, a3,a4..an为前两个数乘积后模10, 所以取前10个数和后10个数的效果是一样, 但是题中要求最小化选出的a1和a2, 因此选择前10个数即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
ll n,L1,R1,L2,R2;
cin>>n>>L1>>R1>>L2>>R2;
vector<ll> a(n+1);
for(ll i=3;i<=n;i++) cin>>a[i];
R1=min(R1,L1+19);
R2=min(R2,L2+10);
bool f=false;
for(a[1]=L1;a[1]<=R1;a[1]++){
for(a[2]=L2;a[2]<=R2;a[2]++){
if(a[3]==(a[1]*a[2])%10){
if(n<4||(n>=4&&(a[2]*a[3])%10==a[4])){
f=true; break;
}
}
}
if(f) break;
}
for(ll i=3;i<=n;i++){
if((a[i-2]*a[i-1])%10!=a[i]) { f=false; break; }
}
if(!f) cout<<"-1"<<" "<<"-1"<<'\n';
else cout<<a[1]<<" "<<a[2]<<'\n';
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
D, 小苯的数字变换
小苯最近在研究一种新型的数字变换游戏,名为“数字螺旋”。给定一个长度为 n 的数字序列 a1,a2,…,an,数字螺旋的生成规则如下:
,∙任意选择一个数字 ai,将其替换为 ai⊕⌊ai2⌋,∙目标是通过最少的操作次数,使得整个序列变成一个回文序列。
现在,小苯需要你帮助他计算出最少需要的操作次数。如果无法达成目标,则输出 −1。
【名词解释】
按位异或(⊕):对两个整数的二进制表示按位按位异或运算。
⌊x⌋:代表对 x 进行下取整操作,得到不超过 x 的最大整数。
回文序列:一个序列被称作回文序列,当且仅当这个序列从左往右读和从右往左读是相同的。换句话说,对于任意的 1≦i≦n,均有 ai=an−i+1 成立。
解题思路:对于你选择的数字ai, 经过与ai/2 , 按位异或后, 多次执行这个操作后, 会重新变回ai,所以原数字中的前后数对, 如果想成功匹配, 必须是在对方的循环里面的, 然后取最小值
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n; cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
int ans=0;
for(int i=1;i<=n/2;i++){
int sum_1=0;
int x=a[i],y=a[n+1-i];
while(x!=y&&sum_1<32){
x=x^x/2;
sum_1++;
}
int sum_2=0;
x=a[i],y=a[n+1-i];
while(x!=y&&sum_2<32){
y=y^y/2;
sum_2++;
}
if(x==y) ans+=min(sum_1,sum_2);
else { cout<<-1<<'\n'; return; }
}
cout<<ans<<'\n';
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
E. 小苯的洞数组构造
一个正整数的“洞数”定义为:其所有数位的洞数之和。例如:299 的洞数是 0+1+1=2。
现在小苯给定了两个正整数 n,sum 希望你帮他构造一个数组 a,满足:
, a 的长度恰好是 n;
, a 中所有数字的值均介于 [1,10^10] 之间,即:1≦ai≦10^10;
, a 中所有数字的和不超过 sum,即:∑iai≦sum,注意是不超过,不是恰好;
,∙a 中所有数字的“洞数”之和尽可能地多。
请你帮他构造一个符合要求的数组 a 吧。
解题思路:通过手动模拟就会发现, 我们在从个位洞数增加的到十位洞数再到百位洞数的过程中只有1 4 8是最优的,类似于1, 4, 8, 48, 88, 488. 888....
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll arr[] = { 1, 4, 8, 48, 88, 488, 888, 4888, 8888, 48888, 88888, 488888, 888888, 4888888, 8888888, 48888888, 88888888, 488888888, 888888888, 4888888888, 8888888888};
void solve(){
ll n,mx;
cin>>n>>mx;
vector<ll> a(n,1);
if(n>mx){
cout<<-1<<endl;
return;
}
ll sum = n;
for(int i=1;i<=20;i++){
for(int j=0;j<=n-1;j++){
ll cost = arr[i]-a[j];
if(sum+cost>mx)break;
a[j] = arr[i];
sum+=cost;
}
}
for(int i=0;i<=n-1;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
F. 小苯的数组计数
小苯认为一个长度为 m 的数组 b1,b2,…,bm 是美丽的,当且仅当其满足以下所有条件:
m≥3;, b1≠bm;, 对于任意 1<i<m,均有:b1>bi 且 bi<bm(即所有中间元素的数值都必须同时小于首位元素和末位元素)。
现在小苯给定了一个长度为 n 的序列 a1,a2,…,an,他想知道 a 中有多少个子数组是美丽的,请你帮他数一数吧。
【名词解释】
子数组:从原数组中,连续的选择一段元素(可以全选、可以不选)得到的新数组。
解题思路:枚举右端点看有多少个合法的左端点, 这个合法的左端点是当前枚举的右端点左侧第一个大于当前数的数,左右端点中间的数都是小于右端点的,实现上是用单调栈
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll arr[] = { 1, 4, 8, 48, 88, 488, 888, 4888, 8888, 48888, 88888, 488888, 888888, 4888888, 8888888, 48888888, 88888888, 488888888, 888888888, 4888888888, 8888888888};
void solve(){
int n;
cin>>n;
vector<ll> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
int ans=0;
vector<ll> stk;
for(int i=1;i<=n;i++){
bool f=0;
while(stk.size()&&a[stk.back()]<=a[i]){
f|=(a[stk.back()]==a[i]);
stk.pop_back();
}
if(stk.size()&&stk.back()<i-1&&!f){
ans++;
}
stk.emplace_back(i);
}
stk.clear();
for(int i=n;i>0;i--){
bool f=0;
while(stk.size()&&a[stk.back()]<=a[i]){
f|=(a[stk.back()]==a[i]);
stk.pop_back();
}
if(stk.size()&&stk.back()>i+1&&!f){
ans++;
}
stk.emplace_back(i);
}
cout<<ans<<'\n';
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
感谢大家的点赞和关注,你们的支持是我创作的动力!
更多推荐
所有评论(0)