太弱了。。。
J - Base Station
Problem Description
移动通信系统中,通信网的建立主要通过基站来完成。
基站可以分为主基站和子基站。子基站和各个移动用户进行连接,子基站必须通过主基站来和外界实现通信。主基站可以覆盖到的范围是一个圆形区域,子基站和主基站的距离小于半径r才能被该主基站覆盖到。半径r由主基站的发射功率确定。
某个区域的移动通信网,包含2个主基站和N个子基站。它们的位置都可以对应到一个整数坐标上。如果子基站至少被一个主基站覆盖,则该子基站是激活的。
现在通信公司在调试设备,它们不停地改变主基站的发射功率,当两个主基站的覆盖半径分别为r1和r2时,需要知道有多少个子基站处于非激活状态。
Input
有若干组输入数据。
第一行是四个整数:x1、y1、x2、y2(1<=x1、y1、x2、y2<=10^9),表示两个主基站的坐标是(x1,y1)和(x2,y2)。
第二行是一个整数N(1<=N<=100000),表示有N个子基站。
接下来的N行,每行两个整数x、y(1<=x, y<=10^9),表示每个子基站的坐标。
接下来一行包含一个整数M(1<=M<=100000),表示有M个询问。
接下来的M行,每行两个整数r1、r2(1<=r1, r2<=10^9),表示询问当两个主基站的覆盖半径为r1和r2时,处于非激活状态的子基站数。Output
对每个查询,输出答案。
Sample Input
1 10 5 2 5 2 6 1 9 3 8 6 7 4 12 5 1 1 3 2 8 2 2 2 3 2
Sample Output
5 3 0 4 3
到两个基站的距离,其实就构成了二维坐标。
其中一个按照顺序加入,另外一维用一维树状数组就可以查询了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
typedef long long LL;
struct node
{
LL x,y;
}p[maxn];
struct circle
{
LL r1,r2;
int id;
}qu[maxn];
LL b[maxn];
int n,c[maxn],q,ans[maxn];
bool cmp1(node a,node b)
{
return a.x>b.x;
}
bool cmp2(circle a,circle b)
{
return a.r1>b.r1;
}
void add(int x,int v)
{
while(x<=n)
{
c[x]+=v;
x+=x&(-x);
}
}
int sum(int x)
{
int res=0;
while(x>0)
{
res+=c[x];
x-=x&(-x);
}
return res;
}
int main()
{
freopen("in.txt","r",stdin);
int x1,y1,x2,y2,x,y;
while(scanf("%d%d%d%d",&x1,&y1,&x2,&y2)!=EOF)
{
scanf("%d",&n);
int tot=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
p[i].x=(LL)(x-x1)*(x-x1)+(LL)(y-y1)*(y-y1);
p[i].y=(LL)(x-x2)*(x-x2)+(LL)(y-y2)*(y-y2);
b[++tot]=p[i].y;
}
scanf("%d",&q);
for(int i=0;i<q;i++)
{
scanf("%lld%lld",&qu[i].r1,&qu[i].r2);
qu[i].r1*=qu[i].r1;
qu[i].r2*=qu[i].r2;
qu[i].id=i;
}
sort(p,p+n,cmp1);//按到第一基站距离从大到小排序
sort(b+1,b+tot+1);
sort(qu,qu+q,cmp2);//按第一基站半径从大到小排序
tot=unique(b+1,b+tot+1)-b-1;
memset(c,0,sizeof(c));//因为前面的排序,所以。。。
int cur=0;
for(int i=0;i<q;i++)
{
while(cur<n&&p[cur].x>=qu[i].r1)//找出在第一个基站外面的
{
int pos=lower_bound(b+1,b+tot+1,p[cur].y)-b;//如果他也在第二个基站外面则这个位置加1
add(pos,1);
cur++;
}
int l=lower_bound(b+1,b+tot+1,qu[i].r2)-b;//找到第二个基站的范围,那么只要减去这个范围内的值就是答案
ans[qu[i].id]=sum(n)-sum(l-1);
}
for(int i=0;i<q;i++)printf("%d\n",ans[i]);
}
return 0;
}
I - 喵喵的IDE
Problem Description
喵喵有一个神奇的IDE,这个IDE自带一个cache,还有一个当前编辑区editarea,初始的时候这个 cache 中有一个字符串 cachebegin。
喵喵想打按照顺序打N个字符串 x,她可以进行三种操作。
打之前 editarea 为空
1、从cache中拿出一个字符串 B直接赋值给editarea , editarea = B.(如果不拿那么不计入操作数)
2、如果editarea里面有字符,那wuyiqi可以删除掉editarea中最后一个字符。(删光了之后就不能删除啦!)
3、喵喵可以在editarea末尾插入一个任意字符。
如果editarea的字符串恰好与她要打的第i个字符串相同,那么她就完成了这次打印,并且这个字符串自动加入cache(cache中可能出现重复字符串),然后editarea自动清空。那么喵喵就会自动进入下一个字符串的打印阶段。
她想问,对于每次字符串输出,最少需要多少次操作。
1 ≤ N ≤ 105 , 字符串长度总和 ∑(Ai) <106 , cache_begin 长度< 100
Input
第一行一个整数T,代表数据组数。
对于每组数据第一行一个整数 N 代表要打印的字符串个数,还有一个字符串cachebegin
以下N 行每行一个字符串 Ai
Ai 和 cachebegin 都只包含小写字母
Output
Sample Input
1 3 a a ab abc
Sample Output
1 2 2
Hint
一开始cache中为{"a"}
第一次操作直接拿出来{"a"}就好了
现在cache为{"a","a"}
拿出来"a",加入b,两次操作。
现在cache为{"a" , "a" , "ab"}
拿出来"ab",加入c。两次操作
唯一 的 Trick 是有可能不从原来的Trie中拿,所以要把答案和本串长度取Min。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010*27;
const int sigma_size=30;
int ch[maxn][sigma_size],val[maxn];
int sz,N;
char s[110];
int idx(char x){return x-'a';}
void insert(char *ss,int len)
{
int u=0;
for(int i=0;i<len;i++)
{
int c=idx(ss[i]);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(sz));
val[sz]=len-i-1;
ch[u][c]=sz++;
}
else val[sz]=min(val[sz],len-1-i);
u=ch[u][c];
}
}
int query(char *ss,int len)
{
int u=0,sum=len;
for(int i=0;i<len;i++)
{
int c=idx(ss[i]);
if(!ch[u][c])break;
else
{
sum=min(sum,val[ch[u][c]]+len-i);
u=ch[u][c];
}
}
return sum;
}
void solve()
{
for(int i=0;i<N;i++)
{
scanf("%s",s);
int len=strlen(s);
int ans=query(s,len);
printf("%d\n",ans);
insert(s,len);
}
}
int main()
{
freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
scanf("%s",s);
int len=strlen(s);
sz=1;
memset(ch[0],0,sizeof(ch[0]));
insert(s,len);
solve();
}
return 0;
}