题目链接:点击查看
A. 回收卫星
单测试点时限: 1.0 秒
内存限制: 256 MB
“这个世上没有无用的齿轮,也只有齿轮本身能决定自己的用途。”
就像太空中的卫星,虽然不计其数,但都各司其职。
但没有一个东西是能够永远无损的。为了便于回收及修理,卫星在故障后会生成一个球形的星场,与之配对的感应器能判断其是否在星场内。
QQ 小方现在要负责卫星的回收工作,他负责使用这些感应器锁定卫星的位置。QQ 小方有卫星基本的运动信息,因此每次工作时,他都能保证自己与卫星保持相对静止,以及自己在星场内。因此,可以将 QQ 小方看作空间直角坐标系的原点 (0,0,0),而星场是一个中心坐标为 (x,y,z) (−109≤x,y,z≤109) ,半径为 r (1≤r≤109) 且包含原点的球,其中 x,y,z,r 都是整数。但接下来,QQ 小方需要你的帮助。
为了回收卫星,QQ 小方每次能向一个整点发射一个感应器,感应器会返回它是否在星场里。由于经费紧张,QQ 小方只能发射不超过 200 个感应器,你能帮助他找到卫星的具体坐标 (x,y,z) 吗?
星场边界上的点视为在星场内部。
交互流程
每一行输出四个整数 0,xi,yi,zi,代表向 (xi,yi,zi) 发射一个感应器。随后,交互程序会输出 1 / 0,代表感应器在 / 不在星场内。
收集足够多的数据之后,输出四个整数 1,x,y,z,代表确定卫星的坐标是 (x,y,z)。之后,你的程序不应再有任何输出。
样例
Input
0
0
0
0
0
0
Output
0 2 0 0
0 -2 0 0
0 0 2 0
0 0 -2 0
0 0 0 2
0 0 0 -2
1 0 0 0
提示
对于样例:
球场的中心是 (0,0,0),半径为 1。
在交互过程中,依次访问了 (2,0,0), (−2,0,0), (0,2,0), (0,−2,0), (0,0,2), (0,0,−2) 六个点,但这六个点都不在球场内。因为原点在球场内,所以球场中心一定位于 (0,0,0),半径为1。(当然,也有可能是运气好,但这个球的中心的确是(0,0,0) 。)
题解:因为原点肯定在球内,所以我们可以二分出上下两个交点,根据弦的性质可得,圆心在两点的垂直平分线上,因此6次二分,即可确定圆心,注意,因为判断的范围在(-2e9,2e9),所以需要用 long long.。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll l,r;
int op;
ll x,y,z;
ll ans;
l=0,r=2e9;
while(l<=r)
{
ll mid=(l+r)>>1;
cout<<0<<" "<<mid<<" "<<0<<" "<<0<<endl;
scanf("%d",&op);
if(op)
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
x=ans;
l=-2e9,r=0;
while(l<=r)
{
ll mid=(l+r)>>1;
cout<<0<<" "<<mid<<" "<<0<<" "<<0<<endl;
scanf("%d",&op);
if(op)
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
x=(ans+x)>>1;
l=0,r=2e9;
while(l<=r)
{
ll mid=(l+r)>>1;
cout<<0<<" "<<0<<" "<<0<<" "<<mid<<endl;
scanf("%d",&op);
if(op)
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
z=ans;
l=-2e9,r=0;
while(l<=r)
{
ll mid=(l+r)>>1;
cout<<0<<" "<<0<<" "<<0<<" "<<mid<<endl;
scanf("%d",&op);
if(op)
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
z=(ans+z)>>1;
l=0,r=2e9;
while(l<=r)
{
ll mid=(l+r)>>1;
cout<<0<<" "<<0<<" "<<mid<<" "<<0<<endl;
scanf("%d",&op);
if(op)
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
y=ans;
l=-2e9,r=0;
while(l<=r)
{
ll mid=(l+r)>>1;
cout<<0<<" "<<0<<" "<<mid<<" "<<0<<endl;
scanf("%d",&op);
if(op)
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
y=(ans+y)>>1;
cout<<1<<" "<<x<<" "<<y<<" "<<z<<endl;
return 0;
}
B. 解题
单测试点时限: 2.0 秒
内存限制: 1024 MB
“我把房门上锁,并非为了不让她进去,而是为了防止自己逃到她身边”。
她又被数学难住了。QQ 小方当然是不会对女生说”不”的。
她的数学题是这样的,她得到了一个十进制大整数,这个大整数只包含 1 - 9 这 9 个数字。
现在,要求选出其中连续的一段数字,把其他未被选中的数字全部变成 0,并且使得变换以后的大整数恰好是 m 的倍数。
QQ 小方为了表现自己的能力,所以一口答应给她写出在所有可能的数里面最小的一个。
但是她的问题太多了,她对于这一个大整数,需要对于 q 个不尽相同的 m 分别给出答案。
但是 QQ 小方自己不会。只能来求助你了,你能帮他解答吗?
输入
第一行包含一个大整数,这个整数的位数为 n (1≤n≤106)。
第二行一个整数 q (1≤q≤500) 代表询问次数。
对于每一个询问,包含一行一个整数,表示第 i 次询问的 mi (1≤mi≤5×107)。
保证 ∑qi=1mi≤5×107 。
输出
对于每一个询问输出两个整数 l,r 表示保留第 l 到第 r 位,如果不存在这样的答案,请输出 -1
。
样例
input
1249
4
7
3
2
83
output
3 4
4 4
3 3
2 4
提示
对于样例:
1249 这个数中,可选出的最小的7的倍数是49,最小的3的倍数是9,2的倍数是40,83的倍数是249。
题解:因为找的一个区间(l,r),所以 l 到末尾 和 r 到末尾 膜m的结果相同,利用这一结论,把每个膜m得到的结果位置标记一下即可,之前出现过直接输出对应位置即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int N=1e6+10;
char s[N];
int q,m,mp[N*50];
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
scanf("%d",&q);
while(q--)
{
// map<int,int> mp;
scanf("%d",&m);
int ans=0,p=1;
int flag=0;
mp[0]=len+1;
for(int i=len;i>=1;i--)
{
ans+=p*(s[i]-'0');
ans%=m;
p=p*10%m;
// cout<<ans<<endl;
if(mp[ans])
{
printf("%d %d\n",i,mp[ans]-1);
flag=1;
break;
}
mp[ans]=i;
}
if(!flag) printf("-1\n");
for(int i=0;i<=m;i++) mp[i]=0;
}
return 0;
}
D. 进制转换
单测试点时限: 2.0 秒
内存限制: 256 MB
“他觉得一个人奋斗更轻松自在。跟没有干劲的人在一起厮混,只会徒增压力。”
QQ 小方决定一个人研究研究进制转换。
很快,QQ 小方就遇到问题了。他现在想知道在十进制范围 [l,r] 内有多少整数满足在 k 进制下末尾恰好有 m 个 0。
比如在十进制下的 24 在二进制下是 11000,我们称十进制下的 24 在二进制下末尾恰好有 3 个 0。
QQ 小方一筹莫展,你能帮他解决问题吗?
输入
第一行包含一个整数 T (1≤T≤105) 表示数据组数。
对于每组数据包含一行,四个整数 l,r,k,m ( 1≤l≤r≤1018, 2≤k,m≤100),含义如题目所述。
输出
对于每组数据输出一行,包含一个整数,表示答案。
样例
input
2
1 10 2 3
1 100 2 3
output
1
6
提示
例如,在 100 进制下,末位是 90 的数不算作有末尾 0。
题解:r以为的符合条件的 - l以为的符合条件的 符合条件为末尾至少为m个0的 - 至少为m+1个0的 我们把乘法运算转化为除法,就可以避免越界了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int N=1e6+10;
int main()
{
int T;
scanf("%d",&T);
ll l,r,k,m;
while(T--)
{
scanf("%lld%lld%lld%lld",&l,&r,&k,&m);
ll n,ans1,ans2;
l--;
n=m;
while(n)
{
n--;
r/=k;
l/=k;
}
ans1=r-r/k;
ans2=l-l/k;
printf("%lld\n",ans1-ans2);
}
return 0;
}
E. 中位数
单测试点时限: 10.0 秒
内存限制: 256 MB
“你的地图是一张白纸,所以即使想决定目的地,也不知道路在哪里。”
QQ 小方最近在自学图论。他突然想出了一个有趣的问题:
一张由 n 个点,m 条边构成的有向无环图。每个点有点权 Ai。QQ 小方想知道所有起点为 1 ,终点为 n 的路径中最大的中位数是多少。
一条路径的中位数指的是:一条路径有 n 个点,将这 n 个点的权值从小到大排序后,排在位置 ⌊n2⌋+1 上的权值。
输入
第 1 行输入两个正整数 n,m (1≤n≤106,1≤m≤106),表示结点数量和边的数量。
第 2 行输入 n 个由空格隔开的整数 Ai (0≤Ai≤109),表示点权。
接下来 m 行,每行输入两个整数 x,y (1≤x,y≤n),表示有一条 x 指向 y 的单向边,保证给出的图是联通的,可能存在重边。
输出
输出一行包含一个整数,表示最大的中位数。如果不存在任何一条起点为 1 ,终点为 n 的路径,则输出 −1 。
样例
input
5 5
1 2 3 4 5
1 2
2 3
3 5
2 4
4 5
output
4
题解:二分枚举下答案,权值大于等于的令其为1,小于的为-1,跑一边最长路,若dis[n] >=0则该情况符合
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int N=1e6+10;
vector<int> v[N];
int val[N],b[N],a[N];
int ans;
int n,m;
struct node{
int to,d;
bool operator <(const node &x)const
{
return d<x.d;
}
};
int dis[N],vis[N];
int judge(int mid)
{
for(int i=0;i<=n;i++)
{
vis[i]=0;
dis[i]=-INF;
}
// cout<<mid<<endl;
priority_queue<node> q;
node tmp,now;
dis[1]=((val[1]>=mid)?1:-1);
vis[1]=1;
tmp.d=dis[1];
tmp.to=1;
q.push(tmp);
while(!q.empty())
{
now=q.top();q.pop();
vis[now.to]=0;
for(int i=0;i<v[now.to].size();i++)
{
int to=v[now.to][i];
if(dis[to]<dis[now.to]+((val[to]>=mid)?1:-1))
{
dis[to]=dis[now.to]+((val[to]>=mid)?1:-1);
if(!vis[to])
{
vis[to]=1;
tmp.to=to;
tmp.d=dis[to];
q.push(tmp);
}
}
}
}
return dis[n]>=0;
}
int main()
{
ans=-1;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
int x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
}
int l=0,r=1e9;
while(l<=r)
{
int mid=(r+l)>>1;
if(judge(mid))
{
l=mid+1;
ans=mid;
}
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
F. 方差
单测试点时限: 2.0 秒
内存限制: 256 MB
“放弃不难,但坚持一定很酷。”
QQ 小方已经在体育馆苦练一天射箭了,但他还在坚持。
QQ 小方每天都要在朋友圈晒自己的训练记录。他一共进行了 n 次射箭,成绩分别是 x1,x2,⋯,xn。为了表现自己的发挥十分稳定,QQ 小方决定选出其中的 m 次成绩,使得他们的方差是所有可以选择的方案中最小的。
对于 m 个元素组成的数列 a1,a2,⋯,am,我们知道他们的方差 σ2=(a1−a¯)2+(a2−a¯)2+⋯+(am−a¯)2m ,其中 a¯=a1+a2+⋯+amm。
但是这个问题对 QQ 小方来说太难了,你需要去帮助 QQ 小方。
为了方便,现在你需要输出这个最小的 σ2 乘以 m2 以后的结果。
输入
输入一行包含两个正整数 n (1≤n≤106) 和 m (1≤m≤n)。接下来一行包含 n 个整数 x1,x2,⋯,xn (1≤xi≤103)。
输出
输出一行包含一个整数,表示答案。为了方便,我们需要输出最小的 σ2 乘以 m2 以后的结果。
样例
input
5 3
1 2 3 4 5
output
6
题解:不一个个写了,直接看题解吧 https://acm.ecnu.edu.cn/blog/entry/320/,不过我当时每台注意,傻逼了,维护了连续m-1个,然后逐渐向后维护的连续m个的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int N=1e6+10;
int n,m;
ll x[N],sum[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&x[i]);
if(m==0) printf("0\n");
else
{
sort(x+1,x+1+n);
for(int i=1;i<=m-1;i++) sum[1]+=x[i];
for(int i=m;i<=n;i++) sum[i-m+2]=sum[i-m+1]-x[i-m+1]+x[i];
ll ans=0,cnt,minn;
for(int i=1;i<=m;i++) ans+=x[i]*x[i]*m;
ans-=(sum[1]+x[m])*(sum[1]+x[m]);
minn=ans;
// cout<<minn<<endl;
for(int i=m+1;i<=n;i++)
{
cnt=ans;
cnt-=x[i-m]*x[i-m]*m-m*x[i]*x[i];
cnt+=(x[i-m]*x[i-m]-x[i]*x[i]+2*x[i-m]*sum[i-m+1]-2*x[i]*sum[i-m+1]);
// cout<<cnt<<endl;
ans=cnt;
minn=min(minn,cnt);
}
printf("%lld\n",minn);
}
return 0;
}