A. Prison Break
题意:给出地图大小n*m 和点 (x,y)问地图上距离该点最远的点是多少
思路:4个角落必然最远 取最大即可
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int T;
cin>>T;
while(T--){
int n,m,x,y;
cin>>n>>m>>x>>y;
cout<<max({x-1+y-1,m-x+n-y,n-x+y-1,x-1+m-y})<<endl;
}
}
B. Repainting Street
题意:长度为n的图 大小为K的刷子 问最少多少次能将图刷为一个颜色
思路:首先一共10种 地图长度是1e5
那么我们直接向后枚举 统计上次颜色出现的位置 和 上次 刷该颜色时颜色最后保留的位置 求出需要刷多少次即可 累加求出结果
最后再以n为结尾点统计一次答案即可
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=1e3+10;
int cnt[N],pre[N],pro[N];
int a[100010];
int main(){
int T;
cin>>T;
while(T--){
int n,k;
scanf("%d%d",&n,&k);
memset(cnt,0,sizeof cnt);
memset(pre,0,sizeof pre);
memset(pro,0,sizeof pro);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
a[i]=x;
if(pre[x]<i-1&&pro[x]<i-1){//上次涂色位置大于K
int t=(i-1-max(pre[x],pro[x])+k-1)/k;//求出需要刷多少次
cnt[x]+=t;
pro[x]=max(pro[x],pre[x])+k*t;
}
pre[x]=i;
}
int ans=0x3f3f3f3f;
for(int i=1;i<=100;i++){
if(pre[i]<n&&pro[i]<n)
cnt[i]+=(n-max(pre[i],pro[i])+k-1)/k;
ans=min(ans,cnt[i]);
}
cout<<ans<<endl;
}
}
C. Bouncing Ball
题意:删除第一个点的时间为y 将一个点变为1的时间为x
求出使得平台的第p个点和分别 第p+k p+2k…个点都能满足这几个位置为1
思路:因为只能删除前面 所以我们考虑从后往前统计
h[i]=h[i+k]+1
和 sum[i]=sum[i+k]+(str[i]=='1')
即位置i为p的话 需要多少个1和位置i有多少个1
这时候我们就知道了 再从前往后推一次 取min
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e5+10;
char str[N];
int sum[N],h[N];
int main(){
int T;
cin>>T;
while(T--){
int n,k,p;
memset(sum,0,sizeof sum);
memset(h,0,sizeof h);
scanf("%d%d%d",&n,&p,&k);
scanf("%s",str+1);
int x,y;
scanf("%d%d",&x,&y);
//cout<<x<<" "<<y<<endl;
int ans=1e9+10;
for(int i=n;i>=1;i--){
h[i]+=h[i+k]+1;
sum[i]+=sum[i+k]+(str[i]=='1');
}
for(int i=1;i<=n;i++){
if(i>=p){
ans=min(ans,y*(i-p)+(h[i]-sum[i])*x);
//cout<<y*(i-p)<<" "<<i-p<<" "<<(h[i]-sum[i])<<" "<<y<<endl;
}
}
cout<<ans<<endl;
}
}
D. XOR-gun
题意:给出一个升序(ai<=aj,i<j)的数组
可以选择2个数将他进行异或运算后加入数组中
可以不断进行该操作 最少多少次操作能使得数组不满足升序
思路:这个并不是个数据结构(字典树)
而需要观察 由于是异或操作 我们考虑二进制
因为每个数均小于1e9
转换为2进制后 最高的数有30位
如果相邻2个数进行异或操作后 他小于左边的数 那么他们这2个数必定高位相同这样异或操作后高位被消去 那么当如果相邻有3个数的最高位相同 那么必然操作数为1 而当超过60个数以后 就必定有相邻有3个数的最高位相同 而这时候 我们只需要考虑小于60的情况 那么我们只要进行枚举即可 不管是3次方 4次方也好。。。都能过
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]^=a[i-1];
}
if(n>=60){
return puts("1"),0;
}
int ans=n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++)
for(int k=i+1;k<=n;k++){
if((a[i]^a[j-1])>(a[i]^a[k]))//(i+1到K k-i-2次)(i-j+1次)
ans=min(ans,k-j-1);
}
}
if(ans!=n)
cout<<ans;
else puts("-1");
return 0;
}