跳马
Description
有一张无穷大,没有边界的棋盘,你要将马从\((0,0)\)移动到\((x,y)\).
每一步你可以使马的横坐标,纵坐标其中一个\(\pm1\),另一个\(\pm2\).
你需要求出最少步数.有\(t\)组数据.
Input
第一行一个正整数\(t\),接下来\(t\)行每行两个整数\(x,y\).
Output
\(t\)行,每行一个整数表示答案.
Sample Input
8
1 2
2 1
1 -2
2 -1
-1 2
-2 -1
-2 1
-1 -2
Sample Output
1 1 1 1 1 1 1 1
HINT
\(1\leq{t}\leq1000,|x|,|y|\leq10^9\).
Solution
100分
打表找个规律.(虽然是可以证明的).
- 表
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define M 8
#define N 1001
using namespace std;
typedef long long ll;
int x[M]={-2,-2,-1,-1,1,1,2,2};
int y[M]={1,-1,2,-2,2,-2,1,-1};
int a[N][N];
queue<int> qx,qy;
inline int read(){
int ret=0;char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c)){
ret=(ret<<1)+(ret<<3)+c-'0';
c=getchar();
}
return ret;
}
inline void bfs(int u,int v){
a[u][v]=1;
qx.push(u);qy.push(v);
while(!qx.empty()){
u=qx.front();qx.pop();
v=qy.front();qy.pop();
for(int i=0,j,k;i<M;++i){
j=u+x[i];k=v+y[i];
if(j>=0&&j<N&&k>=0&&k<N&&!a[j][k]){
a[j][k]=a[u][v]+1;
qx.push(j);qy.push(k);
}
}
}
}
inline void Aireen(){
bfs(20,20);
for(int i=0;i<=40;++i){
for(int j=0;j<=40;++j)
printf("%d\t",a[i][j]-1);
printf("\n");
}
return;
int x,y,t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&x,&y);
printf("%d\n",a[x+20][y+20]-1);
}
}
int main(){
freopen("jump.in","r",stdin);
freopen("test.out","w",stdout);
Aireen();
fclose(stdin);
fclose(stdout);
return 0;
}
- code
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int x,y,t;
inline void Aireen(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&x,&y);
x=abs(x);y=abs(y);
if(x>y) swap(x,y);
if(!x){
if(!y) puts("0");
else if(y==1) puts("3");
else if(y==2) puts("2");
else if(y==3) puts("3");
else printf("%d\n",y/4*2+y%4);
}
else if(y>=(x<<1)){
y-=(x<<1);
printf("%d\n",x+y/4*2+y%4);
}
else if(x>=4){
y-=x;x-=4;
if(!(x%3)){
if(!y) printf("%d\n",(2+x/3)*2);
else printf("%d\n",(2+x/3)*2-1+(y-1)/3+(y-1)%3);
}
else if(x%3==1){
if(!y) printf("%d\n",(2+x/3)*2);
else if(y==1) printf("%d\n",(2+x/3)*2+1);
else printf("%d\n",(2+x/3)*2+(y-2)/3+(y-2)%3);
}
else printf("%d\n",(2+x/3)*2+y/3+y%3);
}
else{
if(x==1) puts("2");
else if(x==2) printf("%d\n",6-y);
else if(x==3) printf("%d\n",y-1);
}
}
}
int main(){
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
Aireen();
fclose(stdin);
fclose(stdout);
return 0;
}
绝对值
Description
有\(n\)个实数\(x_i\),其中\(x_i\)在\([l_i,r_i]\)中均匀随机.
你需要求出\(|\sum{x_i}|\)的期望.答案对\(998244353\)取模.
Input
第一行一个正整数\(n\).接下来\(n\)行每行两个整数\(l_i,r_i\).
Output
一行一个整数表示答案.
Sample Input
2
-2 3
-2 1
Sample Output
199648872
HINT
\(-10^6\leq{l_i}\leq{r_i}\leq{10^6}\).
Solution
100分
我不会...先贴份闫神的题解...
设\(f(i,x)\)表示|前\(i\)个变量的和-\(x\)|的期望.
显然这是一个分段多项式函数,每一段可以通过对\(f(i-1)\)积分得到.
\(f(i)\)的段点为\(f(i-1)\)的段点减去\(l_i\)或加上\(r_i\).
时间复杂度\(O(\sum(2^i\times{i^2}))=O(2^n\times{n^2})\).
序列
Description
给定正整数\(m\)以及长度为\(n\)的序列对\((a_i,b_i)\),你需要将它分为若干段,满足以下\(2\)个条件:
- 若\(i<j\)且\(i\)与\(j\)不在一段中,则\(b_i>a_j\).
- 每一段的\(a\)的最大值之和\(\leq{m}\).
在此基础上,你需要最小化每一段的\(b\)的和的最大值.
Input
第一行两个正整数\(n,m\),接下来\(n\)行每行两个正整数\(a_i,b_i\).
Output
一行一个整数表示答案.
Sample Input
4 6
4 3
3 5
2 5
2 4
Sample Output
9
HINT
\(n\leq100000,m\leq10^{12},1\leq{a_i,b_i}\leq2\times10^9\).
Solution
100分
条件一等价于若\(i<j\)且\(b_i\leq{a_j}\),则\(i\)与\(j\)在一段中.
合并这样的段.
二分每一段的\(b\)的和的最大值\(mx\).
最小化每一段的\(a\)的最大值之和.
\(f[i]\)表示前\(i\)个数的\(a\)的最大值之和的最小值.
\(f[i]=min\{f[j]+mx[j+1][i]\}\).
用\(set\)维护一个\(a\)的下降序列,每次把\(set\)不合法的\(a_i\)弹出.
显然会影响当前决策的是满足\(s[i]-s[j]\leq{mx}\)最小的\(j\),以及\(set\)中的最小值.
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 100005
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
using namespace std;
typedef long long ll;
ll a[N],b[N],f[N],mx[N],m,l,r,mi,mid;
int q[N],h,t,n,cnt;
multiset<ll> s;
inline bool chk(ll k){
ll sum=0ll;int l=0;h=1;t=0;
for(int i=1;i<=n;++i){
while(h<=t&&a[i]>=a[q[t]]){
if(h<t) s.erase(s.find(f[q[t-1]]+a[q[t]]));
--t;
}
q[++t]=i;
if(h<t) s.insert(f[q[t-1]]+a[q[t]]);
sum+=b[i];
while(sum>k) sum-=b[++l];
while(h<=t&&l>=q[h]){
if(h<t) s.erase(s.find(f[q[h]]+a[q[h+1]]));
++h;
}
f[i]=f[l]+a[q[h]];
if(h<t) f[i]=min(f[i],*s.begin());
}
s.clear();
return f[n]<=m;
}
inline void Aireen(){
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;++i)
scanf("%lld%lld",&a[i],&b[i]);
for(int i=n;i;--i)
mx[i]=max(mx[i+1],a[i]);
for(int i=1,j;i<=n;i=j){
mi=b[i];
for(j=i+1;j<=n&&mi<=mx[j];++j)
mi=min(mi,b[j]);
a[++cnt]=a[i];b[cnt]=b[i];
for(int k=i+1;k<j;++k){
a[cnt]=max(a[cnt],a[k]);b[cnt]+=b[k];
}
}
n=cnt;
for(int i=1;i<=n;++i){
l=max(l,b[i]);r+=b[i];
}
while(l<r){
mid=(l+r)>>1;
if(chk(mid)) r=mid;
else l=mid+1;
}
printf("%lld\n",l);
}
int main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
Aireen();
fclose(stdin);
fclose(stdout);
return 0;
}