“深圳计算科研院杯“E起来编程暨第三届湖北省赛
牛客地址
太菜了
A题大水题 输出一行就行 A题
就不粘代码了,这道题看题就会
B题
C题 C题
这道题题意给你一个 n 和 k , xi 的范围是-n到n ,请你求出来表达式的可能方案数
T个样例的累加n为2000,所以直接暴力枚举四个肯定会超时
这里发现等式左边和右边除了k都一样
所以,这里我使用unordered_map先预处理一遍
这道题也,没什么,就需要使用unordered_map预处理
#include <algorithm>
#include <iostream>
#include <cmath>
#include <unordered_map>
using namespace std;
int main(){
ios::sync_with_stdio(false) ; // 加快读入输出
cin.tie(0) ; //解除流绑定
cout.tie(0) ;
int t ;
cin >> t ;
while(t--){
int n, k ;
cin >> n >> k ;
int ans = 0 ;
unordered_map<int,int> um ;
for(int i = - n ; i <= n ; i++){
for(int j = -n ; j <= n ; j++){
um[i * (i + 1) + j * (j + 1)] ++ ; //枚举,结果存入unordered_map
}
}
for(int i = - n ; i <= n ; i++){
for(int j = -n ; j <= n ; j++){
if( (i * (i + 1) + j * (j + 1)) % k != 0 ){
continue ;
}
ans += um[(i * (i + 1) + j * (j + 1)) / k] ; //统计答案
}
}
cout << ans <<endl ;
}
return 0;
}
D 题 D题
题意是 从一个字符串中修改值,使得连续的aa最大
给一个n为字符串长度,k为可修改的最大长度然后一个字符串
输出连续aa的最大值
输出字符串
那么,这道题使用贪心的思路,先修改最短连续不同,,
反证法,如果,不先修改最短的, 那么最后结果产生的连续最长aa一定小于等于先修改最短连续不同
这里使用结构体来存区间(不是a的连续区间)
使用优先队列来优化
最后为什么要前后遍历两遍,主要是特例原字符串中没有出现过a或者只出现过一次a
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std ;
const int N = 5e5 + 100 ;
typedef struct node{
int l,r,d ;
bool operator < (const node t )const { return d > t.d ;} //这里重载小于号为大于号,在优先队列是使用
}Node; //结构体存储边
priority_queue<node> q ; //优先队列优化
char s[N] ; //字符串
int main(){
int n,k ;
cin >> n >> k >> (s + 1) ; //这里s+1是从s[1]的位置读字符串
int last = 0 ;
for(int i = 1 ; i <= n ; i++){
if(s[i] == 'a'){
if(!last){
last = i ;
continue ;
}
Node t; //这里l是区间左端点,r是区间右端点,d是区间长度
t.l = last + 1 ,t.r = i - 1 ,t.d = i - last - 1 ;
if(t.d > 0){ //如果区间长度大于0才入队
q.push(t) ;
}
last = i ;
}
}
while(!q.empty()){
auto t = q.top() ;
q.pop() ;
if(t.d > k){ //如果当前区间数大于还未处理数就break,否则处理
break ; //将该区间内的字符全部置为‘a’,
}
k -= t.d ;
for(int i = t.l ; i <= t.r ; i++){
s[i] = 'a' ;
}
}
if(!last && k){ //处理前端非a区间
s[1] = 'a' ; k-- ;
}
for(int i = 2 ; i <= n ; i++){
if(k && s[i-1] == 'a' && s[i] != 'a'){ //从前遍历一遍
s[i] = 'a' , k-- ;
}
}
for(int i = n - 1 ; i >= 1 ; i--){
if(k && s[i+1] == 'a' && s[i] != 'a'){ //从后面遍历一遍
s[i] = 'a' , k-- ;
}
}
k = 0 ;
for(int i = 2 ; i <= n ; i++){
if(s[i] == 'a' && s[i-1] == 'a'){ //统计连续aa的个数
k++;
}
}
cout << k <<endl << (s + 1) ; //输出
return 0 ;
}
E题 E题
不会
这里先贴上学校大佬写的线性递推,说就套了一下板子 代码
F题 F题
模拟每次出队的过程,,这里每个人的值除以所在队列编号,并且按编号排序后上取整最大值先出队
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std ;
typedef long long ll ;
typedef pair<ll,int> pii ;
vector<int> ans ;
int main(){
int n ;
cin >> n ;
vector<pii> v ;
v.push_back({0,0}) ;
for(int i = 1 ; i <= n ; i++){
ll x ;
cin >>x;
v.push_back({x,i}) ;
}
while(v.size() > 1){
ll t = 1e18 + 1e17 ;
int item = 0 , j ;
for(int i = 1 ; i < v.size(); i++){
if(t > (v[i].first + i - 1) / i ){
t = (v[i].first + i - 1) / i ;
item = v[i].second ;
j = i ;
}
}
for(int i = 1 ; i < v.size() ; i++){
v[i].first -= (t - 1) * i ; //模拟每个人减的数目
}
ans.push_back(item) ; //将该人id加入ans
v.erase(v.begin() + j) ; //出队,由于数据过小,可以使用erase
}
for(size_t i = 0 ; i < ans.size() ; i++){
cout << ans[i] << " " ;
}
cout << endl ;
return 0 ;
}