前言
本次小白月赛据说是AK题,但是蒟蒻考场只做了前三题打卡题,考后优化一下出了第四题,还是太弱了,下面是一些题解。
题解
第一题 小苯的九宫格
打卡题,没什么难度,我利用map打出来了,其实就是对1-9进行重新赋值
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
int x;
map<int,int>a;
for(int i=1;i<=9;i++)
{
cin>>x;
a[i]=x;
}
cin>>s;
for(int i=0;i<s.length();i++)
{
cout<<a[s[i]-48];
}
return 0;
}
第二题 小苯的好数组
需要注意的是不完全相同,所以其实只要出现有逆序的情况就可以将整个串当成好数组,故实际上结果要么是0要么是n,当数组为不减数组或者单个数组时,为0,否则则为1
#include <bits/stdc++.h>
using namespace std;
int a[3000005];
int main()
{
int n;cin>>n;
if(n==1) {cout<<0;return 0;}
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int i=0;i<n-1;i++)
{
if(a[i]>a[i+1]){cout<<n;return 0;}
}
cout<<0;
return 0;
}
第三题 小苯的数字合并
本题我觉得苯人是蒙出来歪打正着了,最开始是只求每个数的后缀和,然后让后缀和去减去前面的a[i-1]然后一个一个求出其中最大值,因为要求极差最大则是让最大值更大,最小值更小,在这种方法里,我将所有的后缀和加起来,让最大值越来越大,且因为是正数,最小数一定是某个单独的元素,并且去逐个求极差,但是后来发现,其实前缀和也要求,毕竟即使ai=ai+ai+1;也可以看作a1=a1+a2变成a2了1,3,5->4,5,反正就是也要求前缀和,然后再一个一个用同样方法求极差,这样前后一起走,就AC了;
#include <bits/stdc++.h>
using namespace std;
long long a[3000005],s[3000005];//a为数组,s为前/后缀和
int main()
{
long long n,ans=0;cin>>n;
if(n==1){cout<<0;return 0;}
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
s[n]=a[n];
for(int i=n-1;i>=1;i--)
{
s[i]=s[i+1]+a[i];//求后缀和
}
for(int i=2;i<=n;i++)
{
ans=max(ans,abs(s[i]-a[i-1]));//比较求极差最大值
}
s[1]=a[1];
for(int i=2;i<=n;i++)
{
s[i]=s[i-1]+a[i];//求前缀和
}
for(int i=1;i<n;i++)
{
ans=max(ans,abs(s[i]-a[i+1]));//同理
}
cout<<ans;
return 0;
}
看了题解之后,他说应该是找某一个最小数的前后的前缀和和后缀和,并且看哪个大,其实就是把我的算法结合了一下,基于最小值一定是某个值,遍历所有情况的思路。需要注意的是,这里一定要用前缀和和后缀和,不然可能会超时。
第四题 小苯的排列构造
这看起来像是数论的问题,我完全沉到了之前见过的一道无锡学院之前出过的题,以为是利用这个结论啥的,结果
发现没啥关系
这道题我们首先可以知道ai-1和pi一起得到了ai,即ai=gcd(ai-1,pi),其实没啥用,但是我们可以由最小公倍数的定义得到关于pi一定是ai的倍数关系,以及ai一定不增的,因为一直在与ai-1求最小公倍数,并且最后一定会减少到1,然后因为gcd(ai,1)=1就一直为1了;所以我们只需要考虑ai!=1的情况就像对于例子4211得到4213,则4=4*1,2=2*1.
对于6333111
6=6*1 , 3=3*1,9=3*3(因为这里3*2=6已经被用过了,所以用3*3=9),12=3*4,然后1之后只要随便输出之前没输出过得数就行,所以我们只需要对ai!=1的ai一直乘就可以求出来pi,但是如果
(下面是优化时间,比赛因为没优化,过了91%卡死了)
对于9 3 3 3******省略一万个3*** 1 1 1 1我们每次都要从3*1,3*2.........3*n直到找到之前没出现过的数,但是其实我们知道后面的数其实不需要再经历3*1,3*2.....只要从上一个数开始找就可以了,会爆掉的,所以这里我用map存储这个3*n已经乘了几次了即n的大小,就过了
#include <bits/stdc++.h>
using namespace std;
int a[200001],s[200001],ans[200001];//a[i]是ai,s[i]是标记i用过了没,ans[i]是pi即答案
int main()
{
map<int,int> c;//c是表示对于一个ai他的对应的pi已经是pi=ai*c,所乘的c的大小
int n,sign=0;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=2;i<=n;i++){
if(a[i-1]%a[i]){cout<<-1;return 0;}//如果不是最小公倍数则不成立直接-1
}
ans[1]=a[1];s[a[1]]=1;
for(int i=2;i<=n;i++)
{
sign=0;
if(a[i]!=1)//对ai不是1的部分进行每次ai乘c直到找到pi的操作
{
if(c[a[i]])c[a[i]]++;
else c[a[i]]=1;
while(s[a[i]*c[a[i]]]&&a[i]*c[a[i]]<=n){c[a[i]]++;}
ans[i]=a[i]*c[a[i]];s[a[i]*c[a[i]]]=1;
}
else {sign=i-1;break;}
}
cout<<ans[1];
for(int i=2;i<=sign;i++)
{
cout<<' '<<ans[i];
}
for(int i=1;i<=n;i++)
{
if(!s[i])cout<<' '<<i;//对是1的部分直接输出未输出的,不用考虑第一个是1的Pi是不是与a(i-1)为gcd=1,因为一定是1
}
return 0;
}
不存在的条件就是ai和ai-1不能整除,那样必然不是 ai=gcd(ai-1,pi),就输出-1即可
第五题 小苯的01背包(easy)
这道题是补出来的,用的题解的期望值贪心法,因为最后的价值为所有价值的与,越与越小的道理,则最后的答案一定小于最大价值,小于2000,则每次枚举价值,判断背包是否小于等于k(反向枚举,直接求出最大值就走)。注意如果没有则输出0。
#include <bits/stdc++.h>
using namespace std;
int n,k,v[20000],w[20000],sign,b;//v体积,w价值
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)
{cin>>v[i]>>w[i];}
for(int i=2000;i>=0;i--)//枚举
{
sign=1;//所选物品容量b
b=2001;//避免一次没改直接输出i=2000
for(int j=0;j<n;j++)
{
if((i&w[j])==i)
{
if(sign){b=v[j];sign=0;}//第一次直接付给b
else b&=v[j];//之后按位与
}
}
/*
此方法不用sign,利用二进制位全为1
b=0xffffffff;//b的二进制位1111111111111111全为1故第一次与得到的就是第一个v[i]
for(int j=0;j<n;j++)
{
if((i&w[j])==i)
{
b&=v[j];
}
}
*/
if(b<=k) {cout<<i;return 0;}
}
cout<<0;//如果没有则输出0
return 0;
}
第六题小苯的01背包(hard)
用试填法,对最后的答案每一位看可否是1,如果上一个可以是1,那就在可以是1的部分里找出下一位的东西,一个学长的代码放这里,有空再补
#include <bits/stdc++.h>
#define int long long
#define pll pair<long long,long long>
#define fi first
#define se second
using namespace std;
const int N=1e6+10,mod=998244353;
int n,m,k;
int res;
int num[N];
int ans[N];
int v[N],w[N];
int book[N];
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
bool flag=1;
for(int o=32;o>=0;o--)
{
int tmp=0,ct=0;
for(int i=1;i<=n;i++)
{
if(book[i]) continue;
if((w[i]>>o)&1)
{
if(ct==0) tmp=v[i];
else
tmp&=v[i];
ct++;
}
}
if((ct)&&(tmp<=m))
{
res|=(1<<o);
for(int i=1;i<=n;i++)
{
if(!((w[i]>>o)&1)) book[i]=1;
}
}
}
cout<<res<<endl;
}
/**
*/