A
时间限制: 1 Sec 内存限制: 128 MB
题目描述
有两个正整数A和B,两个操作+3或者-2。
问,至少多少次操作可以让A变到B
输入
多组数据,第一行一个整数T(1<=T<=5)
两个整数A和B(1<=A,B<=100)
输出
最少操作次数
样例输入
3 10 14 23 23 18 12
样例输出
3 0 3
一道水题,各种方法
我选择了数学方法,最短
#include<cstdio>
#include<iostream>
using namespace std;
int read()
{
int ret=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',
ch=getchar();
return ret;
}
int ans;
int main()
{
int T=read();
while(T--)
{
int u=read(),v=read();
if(v>=u)
{
if((v-u)%3==0) printf("%d\n",(v-u)/3);
if((v-u)%3==2) printf("%d\n",(v-u+4)/3+2);
if((v-u)%3==1) printf("%d\n",(v-u+2)/3+1);
} else
{
if(!((u-v)&1)) printf("%d\n",(u-v)>>1);
else printf("%d\n",((u+3-v)>>1)+1);
}
}
return 0;
}
B
时间限制: 1 Sec 内存限制: 128 MB
题目描述
有一个N*M的迷宫,每个格子是空地或者障碍,现在从一个起点出发,共有2中操作。
1、沿着上、下、左、右4个方向走到相邻的空地上,时间是1
2、沿着上下左右4个方向,跨越障碍,跳到最近的空地上,时间是2
问,从起点到终点最少的时间。如果不能到达输出-1
输入
多组数据,第一行一个整数T(1<=T<=10)
第一行两个整数N和M(1<=N,M<=50),表示地图的大小
接下来N行,每行M个字符,仅包含两种字符“.”和“#”,分别表示空地和障碍
接下来4个整数r1、c1、r2、c2,表示起点和终点的行列。
起点终点保证唯一,且都是空地。
输出
从起点到终点最少时间。
样例输入
2 4 4 .##. .### .### .... 0 0 3 3 2 2 #. .# 0 1 1 0
样例输出
4 -1
宽搜,深搜剪枝,构图跑Dijkstra,SPFA……
忘了初始化堆了。。(我怎么这么菜)
#include<cstdio>
#include<queue>
using namespace std;
int read()
{
int ret=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',
ch=getchar();
return ret;
}
int n,m,cnt;
const int N=105,M=1e6+5;
char s[N];
bool a[N][N],fl[M];
int he[M],w[M],to[M],nxt[M],dis[M];
inline int id(int i,int j)
{
return (i-1)*m+j;
}
struct NA{
int id,x;
};
bool operator >(NA i,NA j)
{
return i.x>j.x;
}
priority_queue<NA,vector<NA>,greater<NA> >q;
inline void add(int u,int v,int k)
{
w[++cnt]=k;
to[cnt]=v;
nxt[cnt]=he[u];
he[u]=cnt;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
a[i][j]=s[j]=='.'?0:1;
}
for(int i=0;i<=id(n,m);i++)
he[i]=0;
cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!a[i][j])
{
if(i!=1&&!a[i-1][j])
add(id(i,j),id(i-1,j),1);
if(i!=n&&!a[i+1][j])
add(id(i,j),id(i+1,j),1);
if(j!=1&&!a[i][j-1])
add(id(i,j),id(i,j-1),1);
if(j!=m&&!a[i][j+1])
add(id(i,j),id(i,j+1),1);
int t;
for(t=i-1;t>=1;t--)
if(!a[t][j]) break;
if(t>0&&t!=i-1&&!a[t][j])
add(id(i,j),id(t,j),2);
for(t=i+1;t<=n;t++)
if(!a[t][j]) break;
if(t<=n&&t!=i+1&&!a[t][j])
add(id(i,j),id(t,j),2);
for(t=j-1;t>=1;t--)
if(!a[i][t]) break;
if(t>0&&t!=j-1&&!a[i][t])
add(id(i,j),id(i,t),2);
for(t=j+1;t<=m;t++)
if(!a[i][t]) break;
if(t<=m&&t!=j+1&&!a[i][t])
add(id(i,j),id(i,t),2);
}
int x=read()+1,y=read()+1;
int xx=read()+1,yy=read()+1;
for(int i=1;i<=id(n,m);i++)
dis[i]=2e9,fl[i]=0;
while(!q.empty()) q.pop();
q.push((NA){id(x,y),dis[id(x,y)]=0});
for(int i=1;i<=id(n,m);i++)
{
while(!q.empty()&&fl[q.top().id]) q.pop();
if(q.empty()) break;
int u=q.top().id;
if(u==id(xx,yy)) break;
q.pop();
fl[u]=1;
for(int e=he[u];e;e=nxt[e])
{
int v=to[e];
if(!fl[v]&&dis[v]>dis[u]+w[e])
q.push((NA){v,dis[v]=dis[u]+w[e]});
}
}
if(dis[id(xx,yy)]==2e9) dis[id(xx,yy)]=-1;
printf("%d\n",dis[id(xx,yy)]);
}
return 0;
}
C
时间限制: 1 Sec 内存限制: 128 MB
题目描述
我们称一个序列A中的某一个数为重数,当且仅当该数在序列中出现的次数超过序列长度的一半。
例如:序列{1,2,1}中,1就是重数。而在序列{1,2,3}和{1,2,1,3}中都不存在重数。
现在给定一个包含n个元素的序列A,每个元素为整数,范围在[0,m-1]。你的任务是统计出包含重数的子区间共有多少个。
由于出题人不想生成大文件。。。输入数据有3个整数构成,分别为n,seed和m。出题人告诉你用如下方法生成数据:
for i = 0 .. n-1:
A[i] = (seed div 2^16) modulo m
seed = (seed * 1103515245 + 12345) modulo 2^31
其中:div表示整除;^表示乘幂;modulo 表示取模
输入
三个整数n(1<=n<=10^5), seed(0<=seed<=2^31-1), m(1<=m<=50)
输出
输出生成的序列中,包含重数的子区间数量
样例输入
5 200 5 10 15 3 8 12345678 1
样例输出
8 23 36
提示
【样例1解释】
A = {0, 0, 1, 2, 0},包含1个元素的子区间有5个
剩下三个分别为{0, 0}、{0, 0, 1}、{0, 0, 1, 2, 0}.
设b【i】【j】表示前i个数中值为j的个数
则题目变成求(l,r),使2(b[r][j]-b[l-1][j])>r-(l-1)的个数
移项得:2b[r][j]-r>2b[l-1][j]-(l-1)
固定右端点,树状数组维护一下即可
mmp,考场上想到了,还剩5分钟,啊……
#include<cstdio>
#define ll long long
using namespace std;
int n,see,m;
const int N=1e5+5;
int a[N],b[N][51],c[(N<<2)+1][51];
ll ans;
inline void add(int bj,int x)
{
for(int i=x;i<=(n<<2);i+=i&-i) c[i][bj]++;
}
inline int getsum(int bj,int x)
{
int ret=0;
for(int i=x;i;i-=i&-i) ret+=c[i][bj];
return ret;
}
int main()
{
scanf("%d%d%d",&n,&see,&m);
for(int i=1;i<=n;i++)
{
a[i]=(see/(1<<16))%m+1;
see=((ll)see*1103515245+12345)%(1<<31);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
b[i][j]=b[i-1][j];
if(a[i]==j) b[i][j]++;
}
ans=0;
int INF=n+1;
for(int j=1;j<=m;j++)
add(j,INF);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
ans+=getsum(j,(b[i][j]<<1)-i-1+INF),
add(j,(b[i][j]<<1)-i+INF);
}
printf("%lld\n",ans);
return 0;
}