HGOI-国庆七连测-day5
题解
今天又是暴力的一天…天天都是暴力暴力…还能不能好好学oi了orz
我又把暴力打崩了orz我还没有找到暴力的精髓
第一题——马里奥(Mario)
【题目描述】
- 给出一个的字符图,#表示浮岛,_表示半空,马里奥可以从相邻的浮岛自由移动,也可以用梯子爬到上下的浮岛上。给出传送门的位置,马里奥的初始位置是在图的左下角。
- 求出梯子最少要多长。
- 这个就是裸暴力嘛…就是二分出长度然后bfs判断是否合法。
- 无奈二分打错(日常)只有60
- orz
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
void fff(){
freopen("mario.in","r",stdin);
freopen("mario.out","w",stdout);
}
const int N=1010;
int n,m,tar_x,tar_y;
bool mp[N][N],vis[N][N];
struct node{
int x,y;
};
bool bfs(int x){
memset(vis,false,sizeof(vis));
int begin_x=n,begin_y=1;
queue<node> q;
vis[begin_x][begin_y]=true;
q.push((node){begin_x,begin_y});
while(!q.empty()){
node temp=q.front();q.pop();
if(temp.x==tar_x&&temp.y==tar_y) return true;
if(temp.y+1<=m&&mp[temp.x][temp.y+1]&&!vis[temp.x][temp.y+1]){
q.push((node){temp.x,temp.y+1});
vis[temp.x][temp.y+1]=true;
}
if(temp.y-1>=1&&mp[temp.x][temp.y-1]&&!vis[temp.x][temp.y-1]){
q.push((node){temp.x,temp.y-1});
vis[temp.x][temp.y-1]=true;
}
for(int i=temp.x+1;i<=min(temp.x+x,n);i++){
if(mp[i][temp.y]&&!vis[i][temp.y]){
q.push((node){i,temp.y});
vis[i][temp.y]=true;
break;
}
}
for(int i=temp.x-1;i>=max(temp.x-x,1);i--){
if(mp[i][temp.y]&&!vis[i][temp.y]){
q.push((node){i,temp.y});
vis[i][temp.y]=true;
break;
}
}
}
return false;
}
char ch[1110];
int main(){
// fff();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
cin>>ch;
for(int j=1;j<=m;j++){
mp[i][j]=(ch[j-1]=='#');
}
}
scanf("%d%d",&tar_x,&tar_y);
int l=0,r=(n-tar_x),ans;
while(l<=r){
int mid=(l+r)>>1;
if(bfs(mid)){
ans=mid;
r=mid-1;
}
else {
ans=mid+1;
l=mid+1;
}
}
cout<<ans;
}
第二题——祭司(priest)
【题目描述】
- 给出组数对范围,要把这些数对范围分成两组,求出两组和之差的最大绝对值最小。
- 我好想题目描述的有点绕。
- 就是一组数对表示一组范围,然后你可以从这个范围里面选值,两个集合当中的和的差最大的最小值就是我们要找的答案。
- 前%的数据,所以暴力就过了
- 后面三十分…dasxxx大佬的猴排居然能够AC…orz随机算法牛逼
- 可以看出,两个集合当中的差最大就是一边全取最大值,另一边全取最小值,然后再反过来就好了。就是某一种分法的答案。
- 那我们记分别为上界和下界之和,记录上下界的和。然后我们就可以看出
- 发现好像是个定值,那就之和有关
- 然后枚举所有可能的情况求最小值就可以了。
- 这个好像想不出正解也分蛮高的。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
void fff(){
freopen("priest.in","r",stdin);
freopen("priest.out","w",stdout);
}
inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
const int INF=80100;
const int N=210;
int n;
struct node{
int l,r;
int sum;
}a[N];
int ans=INF;
bool vis[INF];
int sum1,sum2;
int main(){
// fff();
sum1=0,sum2=0;
n=read();
for(int i=1;i<=n;i++){
a[i].l=read(),a[i].r=read();
a[i].sum=a[i].l+a[i].r;
sum1+=a[i].l,sum2+=a[i].r;
}
vis[0]=true;
for(int i=1;i<=n;i++){
for(int j=INF;j>=a[i].sum;j--){
if(vis[j-a[i].sum]) vis[j]=true;
}
}
for(int i=0;i<=INF;i++){
if(vis[i]) ans=min(ans,max(abs(sum1-i),abs(sum2-i)));
}
cout<<ans;
}
第三题——AK(AK)
【题目描述】
- 给出n个元素与m次查询。
- 每次查询区间的和对2305843008676823040取模,并且对每一个元素进行平方。
- 这个暴力好像有60分的但我分块打炸了…
- 我还是没有掌握暴力的精髓orz
- 看这个模数不像是以前的1e9+7这么和谐,好像有什么玄机…
- 1111111111111111111111111111111100000000000000000000000000000
- 这个是二进制打出来的东西,然后你就发现
- 这个欧几里得拓展定理
- 所以一个数在经过最多59次平方之后就可以不用进行操作了。
- 然后在此之前就暴力分块操作
- 操作完了就直接略过就好了
- 这个分块打打好像还是比较顺的(但我还是打炸了orz)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define LL long long
using namespace std;
void fff(){
freopen("ak.in","r",stdin);
freopen("ak.out","w",stdout);
}
const int N=70000;
const LL MOD=2305843008676823040;
const int LIMIT=66;
inline LL read(){
LL x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
LL n,m;
LL a[N];
inline LL mul(LL x,LL y){
LL ss=0;
while(y){
if(y&1) ss=(ss+x)%MOD;
y>>=1;
x=(x+x)%MOD;
}
return ss;
}
LL block_size;
int belong_block[N];
int vis[N],lim[600];
LL ss[600];
inline LL query(LL l,LL r){
int L=belong_block[l],R=belong_block[r];
LL sum=0;
for(int i=l;i<=min(L*block_size,r);i++) sum=(sum+a[i])%MOD;
//就是这个地方我没有取min....orz
if(L!=R)
for(int i=(R-1)*block_size+1;i<=r;i++) sum=(sum+a[i])%MOD;
for(int i=L+1;i<=R-1;i++) sum=(sum+ss[i])%MOD;
return sum;
}
inline void up_data(LL l,LL r){
int L=belong_block[l],R=belong_block[r];
if(lim[L]<LIMIT){
for(int i=l;i<=min(L*block_size,r);i++){
vis[i]++;
ss[L]=(ss[L]-a[i]+MOD)%MOD;
a[i]=mul(a[i],a[i]);
ss[L]=(ss[L]+a[i])%MOD;
}
lim[L]=999;
for(int i=(L-1)*block_size+1;i<=min(L*block_size,n);i++)
lim[L]=min(lim[L],vis[i]);
}
if(L!=R){
if(lim[R]<LIMIT){
for(int i=(R-1)*block_size+1;i<=r;i++){
vis[i]++;
ss[R]=(ss[R]-a[i]+MOD)%MOD;
a[i]=mul(a[i],a[i]);
ss[R]=(ss[R]+a[i])%MOD;
}
lim[R]=999;
for(int i=(R-1)*block_size+1;i<=min(R*block_size,n);i++)
lim[R]=min(lim[R],vis[i]);
}
}
for(int i=L+1;i<R;i++)
if(lim[i]<LIMIT){
ss[i]=0;
lim[i]=999;
for(int j=(i-1)*block_size+1;j<=i*block_size;j++){
vis[j]++;
lim[i]=min(lim[i],vis[j]);
a[j]=mul(a[j],a[j]);
ss[i]=(ss[i]+a[j])%MOD;
}
}
}
int main(){
// fff();
n=read(),m=read();
block_size=sqrt(n);
for(LL i=1;i<=n;i++){
a[i]=read();
belong_block[i]=((i-1)/block_size)+1;
ss[belong_block[i]]=(ss[belong_block[i]]+a[i])%MOD;
}
while(m--){
LL l,r;
l=read(),r=read();
printf("%lld\n",query(l,r));
up_data(l,r);
}
}