CF1545D AquaMoon and Wrong Coordinate
Luogu 链接
CodeForces 链接
Virtual Judge 链接
题意
本题为 IO 交互题,请注意刷新缓冲区。
题目描述
在一条数轴的正半轴上有 \(n\) 个整点,它们会向正方向做匀速直线运动(速度大小为整数)。现在记录了它们 \(0\) 至 \(T-1\) 的坐标集合(即顺序可能会被打乱),并有一个 \(t_0\)(\(t_0\neq0\))时刻的坐标被修改了。
现在,你需要找出这一时刻 \(t_0\),以及被修改的坐标原本应该是什么。
交互格式
第一行两个正整数 \(n\) 和 \(T\)(\(5\le n\le1000\),\(7\le T\le1000\)),含意见题目描述。
接下来 \(T\) 行每行 \(n\) 个正整数,代表点的坐标 \(x\)(\(1\le x\le10^6\))。
保证 \(1\le v_i\le1000\)。输出仅一行,分别为 \(t_0\) 和修正后的坐标。
思路
记号
- \(x_{t,i}\):\(t\) 时刻第 \(i\) 个点的坐标。
- \(sum_{1,t}\):\(t\) 时刻 \(n\) 个点坐标之和。
- \(sum_v\):\(n\) 个点的速度之和。
- \(sum_{2,t}\):\(t\) 时刻 \(n\) 个点坐标的平方和。
- \(sum_{v^2}\):\(n\) 个点速度的平方和。
找到 \(t_0\)
假设坐标未被修改,则对于任意 \(0<t<T\) 都有 \(\displaystyle sum_v=\sum_{i=1}^n v_i=sum_{1,t}-sum_{1,t-1}\)。因此,我们只需找到不相等的位置,就能找到 \(t_0\)。
具体的,我们可以钦定 \(sum_v=sum_{1,1}-sum_{1,0}\),然后统计有多少与 \(sum_v\) 不相同,并记录第一个与 \(sum_v\) 不同的时刻 \(t_0\)。
若有大于 \(2\) 个时刻与 \(sum_v\) 不相同,则将 \(t_0=1\),并将 \(sum_v\) 修改为 \(sum_{1,3}-sum_{1,2}\)。
找到被修改的坐标
我们发现
而
所以有 \((sum_{2,t+1}-sum_{2,t})-(sum_{2,t}-sum_{2,t-1})=2sum_{v^2}\)。
当 \(t_0<3\) 时,可以得出 \(\displaystyle sum_{v^2}=\frac{sum_{2,3}-2sum_{2,4}+sum_{2,5}}{2}\);否则可以得出 \(\displaystyle sum_{v^2}=\frac{sum_{2,0}-2sum_{2,1}+sum_{2,2}}{2}\)。
一种比较暴力的做法是枚举 \(t_0\) 时刻的所有的坐标,判断修正后是否满足条件。当然还有 \(O(1)\) 的做法。
我们可以假设被修改的坐标为 \(x\),并且我们知道修正的差值 \(\Delta x\)。
根据小学数学知识,我们可以列出一个一元一次方程,然后就可以 \(O(1)\) 求出 \(x\)。
限于篇幅,这里不再赘述,读者可以自己在草稿纸上推一下。
程序
#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<cmath>
#include<iomanip>
#include<string>
#include<stack>
#define ll long long
#define ull unsigned long long
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int MAXN=1000;
const int N=MAXN+10;
//#define more_test
//#define need_init
#ifdef more_test
int T;
#endif
int n,T,x[N][N];
int sum1[N],sum2[N],t0,cnt,dx,sumv,sumv2;bool flag;
void SOLVE(int test_id){
scanf("%d%d",&n,&T);
for(int i=0;i<T;++i)for(int j=1;j<=n;++j)scanf("%d",&x[i][j]);
for(int i=0;i<T;++i)for(int j=1;j<=n;++j)sum1[i]+=x[i][j],sum2[i]+=x[i][j]*x[i][j];
sumv=sum1[1]-sum1[0];
for(int i=2;i<T;++i){
if(sum1[i]-sum1[i-1]!=sum1[1]-sum1[0]){
if(!flag)t0=i,flag=true,dx=sumv-(sum1[i]-sum1[i-1]);
++cnt;
}
}
if(cnt>2)t0=1,sumv=sum1[3]-sum1[2],dx=sumv-(sum1[1]-sum1[0]);
if(t0<3)sumv2=(sum2[3]+sum2[5]-2*sum2[4])/2;
else sumv2=(sum2[2]+sum2[0]-2*sum2[1])/2;
printf("%d ",t0);
if(t0<T-1)printf("%d",(sum2[t0+1]+sum2[t0-1]-2*sum2[t0]-2*sumv2-2*dx*dx)/(4*dx)+dx);
else printf("%d",(2*sum2[T-2]-sum2[T-3]-sum2[T-1]+2*sumv2-dx*dx)/(2*dx)+dx);
fflush(stdout);
}
int main(){
#ifdef need_init
init();
#endif
#ifdef more_test
scanf("%d",&T);
for(int i=1;i<=T;++i)SOLVE(i);
#else
SOLVE(1);
#endif
return 0;
}

浙公网安备 33010602011771号