T1 分糖果
Problem
给出 (L,R,n),求出最大的 (x\% n (Lle xle R))。
Solution
简单的分类讨论。
若 (R-Lge n),说明模 (n) 的余数 (0sim n-1) 都是存在的, 那么答案就是 (n-1)。
若 (R-L<n),这种情况下又有两种情况:
- (lfloor frac{L}{n} floor<lfloorfrac{R}{n} floor)。说明从 (L) 到 (R) 中经过了 (x o n-1 o 0 o y) 的情况。所以答案也是 (n-1)。
- (lfloor frac{L}{n} floor=lfloorfrac{R}{n} floor)。此时不存在 (n-1),因此答案就是 (R\% n)。
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,l,r,c1,c2,d1,d2;
int main()
{
freopen("candy.in","r",stdin);
freopen("candy.out","w",stdout);
scanf("%lld%lld%lld",&n,&l,&r);
if (r-l>=n) printf("%lld
",n-1);
else
{
c1=l/n;c2=l%n;
d1=r/n;d2=r%n;
if (c1==d1) printf("%lld
",d2);
else printf("%lld
",n-1);
}
fclose(stdin);fclose(stdout);
return 0;
}
T2 插入排序
Problem
给出一个含有 (n) 个元素的数组 (a)。有 (m) 次操作,每次可以修改某个数的值或者查询某个数的排名。
修改操作最多 5000 次。
Solution
这题原本跟平衡树有点关系,但是看到限制:
至多有 5000 次操作属于类型一。
最多进行 5000 次修改。这意味着一次修改后求出所有元素的排名,到下次修改前的查询都是可以 (O(1)) 查询的。
那么我们只需要 (O(n)) 修改就可以轻松通过此题。
可以先预处理出每个数的排名,每次修改判断改后的值和改前的值的大小关系,选择向后还是向前修改。
Code
#include<bits/stdc++.h>
#define N 8005
using namespace std;
struct node
{
int id,val;
}a[N];
int n,q,x,y,opt,rk[N];
bool lst;
bool cmp(node x,node y)
{
if (x.val<y.val) return true;
if (x.val>y.val) return false;
return x.id<y.id;
}
int main()
{
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
scanf("%d%d",&n,&q);
for (int i=1;i<=n;++i)
scanf("%d",&a[i].val),a[i].id=i;
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;++i)
rk[a[i].id]=i;
while (q--)
{
scanf("%d",&opt);
if (opt==1)
{
scanf("%d%d",&x,&y);
x=rk[x];
if (y<a[x].val)
{
a[x].val=y;
for (int i=x-1;i;--i)
{
if (a[i].val>a[i+1].val||(a[i].val==a[i+1].val&&a[i].id>a[i+1].id))
{
node t;
t=a[i];a[i]=a[i+1];a[i+1]=t;
}
}
}
else if (y>a[x].val)
{
a[x].val=y;
for (int i=x;i<n;++i)
{
if (a[i].val>a[i+1].val||(a[i].val==a[i+1].val&&a[i].id>a[i+1].id))
{
node t;
t=a[i];a[i]=a[i+1];a[i+1]=t;
}
}
}
for (int i=1;i<=n;++i)
rk[a[i].id]=i;
}
if (opt==2)
{
scanf("%d",&x);
printf("%d
",rk[x]);
}
}
fclose(stdin);fclose(stdout);
return 0;
}
T3 网络连接
Problem
有 (n) 台计算机,每台要么为服务机要么为用户机。
每台计算机有一个地址 (s),形如 (a.b.c.d:e),满足 (0le a,b,c,dle 255,0le ele 65535),且 (a,b,c,d,e) 都没有前导 0。
对于每台服务机,若地址不合法输出 ( ext{ERR}),若地址已经出现过输出 ( ext{FAIL}),否则输出 ( ext{OK})。
对于每台客户机,若地址不合法输出 ( ext{ERR}),若地址出现过则输出对应服务机,否则输出( ext{FAIL})。
Solution
比较明显的一个哈希。
首先先判断地址的合法性,注意前导0,(a,b,c,d,e) 的大小范围和 (.) 以及 (:) 的个数。
将 (a,b,c,d,e) 拼起来成为一个长度最大为 17 的数字,可以用 ( ext{long long}) 存储。
判断该数字是否出现过,并根据计算机的类型输出对应的答案。
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,sum,num1,num2,x,y,opt;
ll res;
bool bj;
char ch,lst,llst;
struct node
{
int id;
ll val;
}h[19260820];
void charu(ll val,int id)
{
ll s=val%19260817;
while (h[s].val)
{
if (h[s].val==s)
{
x=2;
return;
}
++s;
if (s==19260817) s=0;
}
h[s].val=s;
h[s].id=id;
x=1;
}
void chazhao(ll val)
{
ll s=val%19260817;
while (h[s].val)
{
if (h[s].val==s)
{
y=h[s].id;
x=1;
return;
}
}
x=2;
}
int main()
{
freopen("network.in","r",stdin);
freopen("network.out","w",stdout);
scanf("%d",&n);
ch=getchar();
for (int i=1;i<=n;++i)
{
while (ch!='S'&&ch!='C') ch=getchar();
if (ch=='S') opt=1;
else opt=2;
while ((ch<'0'||ch>'9')&&ch!='.'&&ch!=':') ch=getchar();
bj=true;num1=num2=0;sum=0;res=0;
lst=' ';llst=' ';
while ((ch>='0'&&ch<='9')||ch=='.'||ch==':')
{
if (ch>='0'&&ch<='9'&&lst=='0'&&(llst=='.'||llst==':'||llst==' ')) bj=false;
if ((ch=='.'||ch==':'||ch==' ')&&(lst=='.'||lst==':'||lst==' ')) bj=false;
if (ch>='0'&&ch<='9')
{
if (sum<=65535) sum=sum*10+(ch-'0'),res=res*10+(ch-'0');
}
else
{
if (sum>255) bj=false;
sum=0;
if (ch=='.') ++num1;
if (ch==':')
{
++num2;
if (num1!=3) bj=false;
}
}
llst=lst;lst=ch;
ch=getchar();
}
if (sum>65535||!bj||num1!=3||num2!=1||lst==':') printf("ERR
");
else
{
x=y=0;
if (opt==1)
{
charu(res,i);
if (x==1) printf("OK
");
else printf("FAIL
");
}
else
{
chazhao(res);
if (x==1) printf("%d
",y);
else printf("FAIL
");
}
}
}
fclose(stdin);fclose(stdout);
return 0;
}
T4 小熊的果篮
Problem
给出一个长度为 (n) 的 01 串,每次删除连续的 1 或 0 的第一个 1/0 ,问每次删去的数字的编号。
注意删除数字后存在原本不连续的变得连续。
Solution
考虑将每个块合并,例如样例 2 就可以合并成 4 3 3 2 1 1 2 4。
把各个块存入队列中,每次取出各个块的首位,更新,合并。
考虑时间复杂度,有一种卡到最劣的构造是 1 2 3 4…… (sqrt{n}) 。
易证这种情况下的时间复杂度为 (mathcal{O}(nsqrt{n}))。
Code
#include<queue>
#include<cstdio>
#define N 200005
using namespace std;
struct node
{
int st,ed,cl;
};
queue<node> q,qq;
int n,num,c[N];
bool b[N];
int main()
{
freopen("fruit.in","r",stdin);
freopen("fruit.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&c[i]);
c[n+1]=1-c[n];
for (int i=2,lst=1;i<=n+1;++i)
if (c[i]!=c[i-1]) q.push((node){lst,i-1,c[i-1]}),lst=i;
num=n;
while (num)
{
while (!q.empty())
{
node x=q.front();
q.pop();
while (b[x.st]&&x.st<=x.ed) x.st++;
if (x.st>x.ed) continue;
printf("%d ",x.st);
--num;b[x.st]=true;
if (x.st==x.ed) continue;
x.st++;
qq.push(x);
}
printf("
");
while (!qq.empty())
{
node x=qq.front();
qq.pop();
while (!qq.empty())
{
node y=qq.front();
if (x.cl==y.cl)
{
x.ed=y.ed;
qq.pop();
}
else break;
}
q.push(x);
}
}
return 0;
}