CSP-J 2021 题解
A 分糖果
考虑分类讨论。
假如 \(\lfloor\frac{l}{n}\rfloor\not=\lfloor\frac{r}{n}\rfloor\),则可以发现其中一定存在一个数 \(\bmod n=n-1\),因此直接输出 \(n-1\)。
否则,选择 \(r\) 的答案一定是最优的,输出 \(r\bmod n\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,l,r;
signed main()
{
scanf("%lld%lld%lld",&n,&l,&r);
if(l/n==r/n)
printf("%lld\n",r%n);
else
printf("%lld\n",n-1);
return 0;
}
B 插入排序
注意到 \(n\) 和操作 \(1\) 次数都非常的小,考虑暴力操作。
预处理出每个数有多少个数比它小,修改的时候暴力更改新数在原序列中的关系,查询可以直接得出结果。
#include<bits/stdc++.h>
using namespace std;
int n,q;
int a[100010],rk[100010];
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[j]<a[i]||(a[j]==a[i]&&j<i))
rk[i]++;
while(q--)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int x,y;
scanf("%d%d",&x,&y);
for(int i=1;i<=n;i++)
if(a[i]>a[x]||(a[i]==a[x]&&i>x))
rk[i]--;
rk[x]=0;
a[x]=y;
for(int i=1;i<=n;i++)
if(a[i]>a[x]||(a[i]==a[x]&&i>x))
rk[i]++;
for(int i=1;i<=n;i++)
if(a[i]<a[x]||(a[x]==a[i]&&i<x))
rk[x]++;
}
else
{
int x;
scanf("%d",&x);
printf("%d\n",rk[x]+1);
}
}
return 0;
}
C 网络连接
毒瘤大模拟。
对于一个服务器,考虑先判定串合法性,然后用 map
维护对应的串的出现情况。
对于客户端也是类似的,只要判定合法然后就可以在 map
中查询对应串的出现位置。
判定合法的时候有比较多的细节,需要仔细一些。
#include<bits/stdc++.h>
using namespace std;
int n;
map<string,int> mp;
string tp,id;
int getnumber(string x,int l,int r,int lim)
{
if(l>r)
return -1;
if(r-l+1>lim)
return -1;
if(l!=r&&x[l]=='0')
return -1;
for(int i=l;i<=r;i++)
if(x[i]<'0'||x[i]>'9')
return -1;
int res=0;
for(int i=l;i<=r;i++)
res=res*10+x[i]-'0';
return res;
}
bool check(string x)
{
int cntdian=0,cntmao=0,lstdian=-1;
for(int i=0;i<x.length();i++)
{
if(x[i]=='.')
{
cntdian++;
if(cntdian>3||cntmao!=0)
return 0;
}
if(x[i]==':')
{
cntmao++;
if(cntdian!=3||cntmao>1)
return 0;
}
}
if(cntdian!=3||cntmao!=1)
return 0;
for(int i=0;i<x.length();i++)
{
if(x[i]=='.'||x[i]==':')
{
int res=getnumber(x,lstdian+1,i-1,3);
if(res==-1||res>255)
return 0;
lstdian=i;
}
}
int res=getnumber(x,lstdian+1,x.length()-1,5);
if(res==-1||res>65535)
return 0;
return 1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>tp>>id;
if(tp=="Server")
{
if(!check(id))
cout<<"ERR\n";
else if(mp[id])
cout<<"FAIL\n";
else
mp[id]=i,cout<<"OK\n";
}
else if(tp=="Client")
{
if(!check(id))
cout<<"ERR\n";
else if(!mp[id])
cout<<"FAIL\n";
else
cout<<mp[id]<<'\n';
}
}
return 0;
}
D 小熊的果篮
首先预处理出在第一轮哪些水果会被选出。
可以注意到一个水果在第 \(i\) 轮被删除的必要条件是 \(i=1\) 或前一个数在 \(i-1\) 轮被删除了。
因此在每一轮删除的时候,暴力判断下一个数是否要在下一轮被删除即可。
#include<bits/stdc++.h>
using namespace std;
int n,a[500010],lst[500010],nxt[500010];
bool in[500010];
int re[500010],cnt=0,kkk;
int pe[500010],tot=0;
int main()
{
a[0]=-1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),nxt[i]=i+1,lst[i]=i-1;kkk=n;
nxt[0]=1;in[n+1]=1;
lst[n+1]=n;
for(int i=1;i<=n;i++)
if(a[i]!=a[i-1])
re[++cnt]=i,in[i]=1;
while(1)
{
if(kkk==0)
return 0;
for(int i=1;i<=cnt;i++)
{
printf("%d",re[i]);kkk--;
if(i!=cnt)
putchar(' ');
lst[nxt[re[i]]]=lst[re[i]];
nxt[lst[re[i]]]=nxt[re[i]];
if(in[nxt[re[i]]]==0&&a[nxt[re[i]]]!=a[lst[re[i]]])
pe[++tot]=nxt[re[i]],in[nxt[re[i]]]=1;
}
cnt=tot;
for(int i=1;i<=tot;i++)
re[i]=pe[i];
tot=0;
puts("");
}
return 0;
}