2024.07.13科大讯飞提前批
1. 找01
牛牛拥有一个长度为 n 的01 串,现在他想知道,对于每个字符,在它前面的最近的不同字符的下标是多少?
两个下标记录上一个01位置
int main(int argc, char *argv[]) {
int T;
cin>>T;//测试组数
while(T--){
int n;
cin>>n;
string s;
cin>>s;
int idx0 =- 1; int idx1 = -1;//分贝记录上一个0和1的位置
vector<int> res(n,-1);
for(int i=0;i<n;i++){//遍历所有字符
if(s[i]=='0'){
res[i] = idx1;
idx0 = i;
}
else{
res[i] = idx0;
idx1 = i;
}
}
for(int i=0;i<n;i++){
if(i>0) cout<<" ";
if(res[i]==-1) cout<<res[i];
else cout<<res[i]+1;
}
cout<<endl;
}
return 0;
}
2. 不能出现太多
给定n个数字A1,A2,..An,请求出这些数字中出现次数小于等于k的最小的数。
先哈希计数再筛选可以避免排序
int main(int argc, char *argv[]) {
int n; int k;
cin>>n;
cin>>k;
vector<int> nums(n);
unordered_map<int,int> m;
for(int i=0;i<n;i++){
cin>>nums[i];
m[nums[i]]++;
}
int res = INT_MAX;
for(auto num:nums){
if(m[num]>k) continue;
res = min(res,num);
}
if(res==INT_MAX) cout<<-1;
else cout<<res;
return 0;
}
3. 乘2除2
给出一个大小为n的序列a,每次操作可以选择序列a中的一个数x,把x变成x*2或者[x/2](对同一个a可以操作多次但不能既进行乘操作又进行除操作)。
问最少操作多少次使得a是不下降的。
因为这里操作后是倍增,可以动态规划,同时记录每一位经过任意除和乘操作后得到的数以及对应次数,接着下一个数可以从该状态转移
const long long MAXN = 1e18;
unordered_map<long long,int> dp[20005];//暴力哈希列举所有操作次数
int main(int argc, char *argv[]) {
int n;
cin>>n;
vector<int> nums(n);
for(int i=0;i<n;i++)
cin>>nums[i];
//考虑到最小操作次数的无后效性,可以使用动态规划,其实暴力列举所有操作次数的可能,然后转移到下一个状态记录列举即可
dp[0][1] = 0;//不进行任何操作,初始操作数为0
for(int i=0;i<n;i++){//遍历数字序列
for(auto &[j,steps]:dp[i]){//从上一个状态开始转移,初始状态时最小值1,操作次数为0
if(nums[i]>=j){//已经递增的话,可以选择不变,变小
if(dp[i+1].find(nums[i])==dp[i+1].end()||dp[i+1][nums[i]]>steps)
dp[i+1][nums[i]] = steps;
//变小
long long num = nums[i];
int cnt = 0;
while(num/2>=j){
cnt++;
num/=2;
if(dp[i+1].find(num)==dp[i+1].end()||dp[i+1][num]>steps+cnt)
dp[i+1][num] = steps+cnt;
}
}
else{//否则只能选择变大维持递增
long long num = nums[i];
int cnt = 0;
while(num<j){
num*=2;
cnt++;
}
if(dp[i+1].find(num)==dp[i+1].end()||dp[i+1][num]>steps+cnt)
dp[i+1][num]=steps+cnt;
}
}
}
int res = INT_MAX;
for(auto &[k,v]:dp[n])
res = min(res,v);
cout<<res;
return 0;
}