1,分糖果

分析:本题是初赛第一题,按照以往经验,这一题一般是小模拟题或者数学题。
我们可以发现本题的大意是要求我们那一些糖果并分给n个人,直到糖果数小于n。
看得出来,本题的考察范围是数学计算,如果我们能找到通用公式计算,就可以避免模拟。其核心思路就是取余和特判,如果l和r达到某某要求,则使用特别公式。
解题思路:我们可以分析一下,由于题目的特殊性质,这道题我们直接使用区域公式计算的同时,也有某些情况无需计算,只需直接输出n即可。
题目的核心是在[l,r]区间中找一个数k,使得k % n最大。
当l和r于同一个周期内,说明其中所有值%n的值都相同,我们就可以输出r%n代表所以区间内值的最优。、
反之,不在同一个周期内,则小朋友会一直那直到小于n,这样最大只有n-1,就输出理论极限n-1。
我们来模拟下样例,证明思路。
7 16 23,16和23不在同一周期,则输出理论极限n-1,即6,正确。
样例通过证明我们的思路正确,接下来构造代码:
#include<bits/stdc++.h>
using namespace std;
long long n,l,r;//初始化
int main(){
cin>>n>>l>>r;//输入
if (l/n!=r/n)//跨越周期,输入理论极限
cout<<n-1;
else cout<<r%n;//在同一个周期内,余数随着数字的增大而严格单调递增,商相同,我们只需输出区间最大值r取余n的区间公共余数即可
return 0;
}
2,插入排序


分析:本题要求输入一个数组,然后进行q次查询,排序或改值。
不难看出来,这是一道大模拟题或者交互题。
每次进行查询,然后进行相对修改即可。
注意一个要点,本题的排序操作不可以永久修改。
然后我们对样例模拟一下,证明我们的思路。
3 4为首先输入的两个。
3 2 1为输入的序列。
接下来4行输入。
2 3,插入排序并输出原来第3个元素的新位置,由于进行了排序,a被排到了第一个,输出1。
1 3 2,3的位置变为2,现在是3 2 2。
2 2,2的位置是2,经排序后相对位置不变,为1。
2 3,3的位置为2,经排序后相对位置不变,为2。
样例证明我们的猜想是正确的,接下来我们来构建代码:
#include<bits/stdc++.h>
using namespace std;
struct Node{
int m;
bool f;//定义标记结构体
};
int n,q,a[8020];//初始化
int main(){
cin>>n>>q;
for (int i = 1;i <= n;i++){
cin>>a[i];//输入
}
while (q–){//q次查询
int w;cin>>w;
if (w == 1){//路径1
int x,v;
cin>>x>>v;
a[x] = v;//修改
continue;//跳过
}
int x;cin>>x;Node b[8020];//标记数组
for (int i = 1;i <= n;i++){
b[i].m = a[i];
b[i].f = false;//标记给定下标
}
b[x].f = true;//修改
for (int i = 1;i <= n;i++)
for (int j = i;j >= 2;j–)
if (b[j].m < b[j-1].m)
swap(b[j-1],b[j]);//插入排序
for (int i = 1;i <= n;i++){
if (b[i].f == true){//查找下标
cout<<i<<endl;
break;
}
}
}
return 0;
}
然而我们发现这题因为样例很大,此做法只有50分。
接下来我们来优化。
这道题的TLE罪魁祸首是排序,导致代码复杂度变为O(n^n),如果我们能够修改代码变为去除循环内的代码,则复杂度为O(n),就可以通过。
我们可以将插入排序转换为局部的修改,这样可以达到线性复杂度。
我们可以新建一个映射,这个映射包含排序前的内容,可以保存信息。
然后我们每次修改只需对表修改,对局部进行插入即可。
每次我们进行1操作时,更新原数组,更新复制数组,然后扫描数组,找到局部可插入位置插入,并重新映射,修改原数组即可,这样2操作只要查询即可。
#include<bits/stdc++.h>
using namespace std;
int n,q;
vector<pair<int,int>> a;//原数组
vector<pair<int,int>> temp;复制数组
int main(){
cin>>n>>q;
for (int i = 0;i < n;i++){//输入
int x;cin>>x;
a.push_back({x,i});//插入信息
}temp = a;
sort(temp.begin(),temp.end());//排一次序保证以后局部有序
vector<int> pos(n);//映射数组
for (int i = 0;i < n;i++)
pos[temp[i].second]=i;//映射
while (q–){//多次操作
int k;
cin>>k;
if (k == 1){
int x,y;cin>>x>>y;
x–;
int p=pos[x];//找到旧元素在temp中的位置
for(int i=p;i<temp.size()-1;i++)
temp[i] = temp[i+1];//后面的元素整体前移,覆盖掉旧元素
temp.pop_back();//删除尾部多余元素
for (int i = p;i < temp.size();i++)
pos[temp[i].second]=i;//更新映射
a[x].first = y;//更新原数组值
int ispos = 0;//线性扫描,找到新值应该插入的位置
while (ispos<temp.size()&&temp[ispos]<a[x])
ispos++;
temp.push_back({0,0});//更新复制数组
for (int i=temp.size()-1;i>ispos;i–)
temp[i] = temp[i-1];//从后往前移动元素,腾出ispos位置
temp[ispos] = a[x];//插入新元素
for (int i = ispos;i < temp.size();i++)
pos[temp[i].second] = i;//建立新映射
}else{
int x;//因为每次修改都更新,所以这里只需直接查询即可
cin>>x;
x–;
cout<<pos[x]+1<<endl;//下标对齐
}
}
}
3,网络连接




分析:不愧是绿题,连描述都那么长。
实则翻译过来,只有几句话。
核心意思:给定任意个机器,每台机器有一个独立ip号。
若是服务器,则新建服务并查看,如果格式正确且ip没有被占用,则是一个可用的端口号,注册新服务器。
若是客户端,则判断加入的ip是否存在,如果是,则加入并输出改ip服务器的编号,否则报错。
每一台机器都有一个独立编号,比上一个+1。
这大概就是题目意思。
我们来模拟下样例。
第一个,server且格式正确,建立服务器。
第二个,ip被占用,所以输出FAIL。
第三个,ip正确,加入并输出编号。
第四个,不存在服务器,所以报错FAIL。
第五个,格式错误,直接报ERR。
这就是我们的想法,完全一样!
接下来展示代码:
#include<bits/stdc++.h>
using namespace std;
struct Node{
string j;//状态结构体
int id;
};
int n;
bool check(string ip){
int cnt1 = 0,cnt2 = 0;
for (int i = 0;i < ip.size();i++){
if (ip[i] == '.')
cnt1++;
if (ip[i] == ':')//统计符号数量
cnt2++;
}
if (cnt1 != 3)
return false;
if (cnt2 != 1)
return false;//不对剔除
string be = "";//线性字符串扫描(be用来存之前截下来的)
for (int i = 0;i < ip.size();i++){//扫描
if (ip[i] == '.' || ip[i] == ':'){//是符号
if (be.empty()) return false;//符号前的内容是空,剔除
if (be.size() > 1 && be[0] == '0')
return false;//前导0太多,剔除
for (int j = 0;j < be.size();j++)
if (!isdigit(be[j])) //不是数字
return false;//剔除
long long num = stoll(be);//字符串转long long
if (num < 0 || num > 255) //超出范围,剔除
return false;
be = "";
}else be += ip[i];//累加以便判断
}
if (be.empty()) return false;//最后一段为空,剔除
if (be.size() > 1 && be[0] == '0') return false;//前导0太多,剔除
for (int j = 0;j < be.size();j++)
if (!isdigit(be[j])) return false;//不是数字
long long num = stoll(be);//转换类型
if (num < 0 || num > 65535) return false;//范围不符合
return true;//正确的地址
}
pair<bool,int> in(string ip,vector<Node> a){//当前地址是否存在
for (int i = 0;i < a.size();i++)
if (ip == a[i].j)
return {true,a[i].id};//返回
return {false,-1};
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);cin>>n;
vector<Node> a;//服务器数组
int i = 1;//编号
while (n–){
string m;cin>>m;
string ip;cin>>ip;//输入
if (!check(ip))//不是正确地址
cout<<"ERR"<<endl;
else if (m == "Server"){//服务器
auto ans = in(ip,a);//当前地址状态
if (ans.first){
cout<<"FAIL"<<endl;//已经存在,这次申请失效
}else{
cout<<"OK"<<endl;//申请成功
a.push_back({ip,i});//更新
}
}else if (m == "Client"){//客户端
auto ans = in(ip,a);
if (ans.first)//存在
cout<<ans.second<<endl;//成功访问,输出编号
else cout<<"FAIL"<<endl;//失败,没有地址
}
i++;//编号累加
}
return 0;
}
完成了,现在分数来到了300分(一等奖)!

