简单模拟题
但是还是因为少考虑了一点,wa了一发
给了两秒,暴力足够了
#include
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
typedef long long ll;
int main(){
ll a,b,n;
scanf("%lld%lld%lld",&a,&b,&n);
if(b==n){//b无需再移动,只需要把a一次移过去就好
printf("1\n");
return 0;
}
ll c=b-a;
ll ans=0;
int f1=0;
int f2=0;
while(1){
if(f1==0){
a+=c;//移动a
ans++;
}
if(a>=n) f1=1;
if(f2==0){
b+=c;//移动b
ans++;
}
if(b>=n) f2=1;
if(f1&&f2) break;
}
printf("%lld\n",ans);
return 0;
}
给出一个长度为 n n n的数组, a 1 , a 2 , ⋯ , a n a_1,a_2,\cdots ,a_n a1,a2,⋯,an ( 1 ≤ a i ≤ 1 0 9 ) (1\leq a_i\leq 10^9) (1≤ai≤109)
求满足以下条件的 i , j , k i,j,k i,j,k有多少对。
对于 1 ≤ i < j < k ≤ n 1\leq i1≤i<j<k≤n 有 a k − a j = a j − a i a_k-a_j=a_j-a_i ak−aj=aj−ai
思路:
三个变元,第一想法减少变元
时间给了两秒,可以先确定其中两个变元的取值,计算出第三个,然后去找该值有多少个即可。
枚举 a i , a j a_i,a_j ai,aj的值,我们需要知道下标在 j j j之后的元素中有多少个等于 2 a j − a i 2a_j-a_i 2aj−ai。
正序遍历不太好处理,那就倒序遍历,每枚举一个 a j a_j aj,用map统计其个数即可(这时候map统计的都是出现在 j j j后面的值)。
#include
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> P;
const int mod=1e9+7;
unordered_map<int,int>mp;
int a[maxn];
int main(){
int t;
scanf("%d",&t);
while(t--){
mp.clear();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int ans=0;
for(int j=n;j>=1;j--){
for(int i=j-1;i>=1;i--){
int ak=2*a[j]-a[i];
ans+=mp[ak];
}
mp[a[j]]++;
}
printf("%d\n",ans);
}
return 0;
}
金字塔底部有四条边,两条边从北指向南(平行于y轴),两条边从东指向西(平行于x轴)。
完美的平衡金字塔斜面和底面的夹角成45°。
现有 n n n个obelisk,给出其位置坐标 ( x i , y i ) (x_i,y_i) (xi,yi)和高度 h i h_i hi。试求能将这些obelisk全部包含进去的最小的金字塔,并给出其中心坐标。
思路:
“夹角为45°”—>四棱锥的高=其底面正方形边长的一半
可将高转化成底面上的边长
#include
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> P;
const int mod=1e9+7;
unordered_map<int,int>mp;
int a[maxn];
int main(){
int n;
cin>>n;
int lx=INF,rx=-INF;
int ly=INF,ry=-INF;
for(int i=1;i<=n;i++){
int x,y,h;
cin>>x>>y>>h;
lx=min(lx,x-h);
rx=max(rx,x+h);
ly=min(ly,y-h);
ry=max(ry,y+h);
}
int ans_x=(lx+rx)/2;
int ans_y=(ly+ry)/2;
int ans_h=(max(rx-lx,ry-ly)+1)/2;
cout<<ans_x<<" "<<ans_y<<" "<<ans_h<<endl;
return 0;
}
给定一棵树和树上一些点,求任意一个树上到所有给定点距离相等的点。
多源BFS
bfs 按层维护
记录每个点在同一层被多少个点覆盖
#include
using namespace std;
const int maxn=2e5+10;
const int INF=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> P;
typedef pair<P,int> PP;
const int mod=1e9+7;
int n,m;
int h[maxn],nxt[maxn<<1],e[maxn<<1],cnt;
int vis[maxn],lev[maxn],num[maxn];
void add(int a,int b){
e[cnt]=b;
nxt[cnt]=h[a];
h[a]=cnt++;
}
void bfs(){
queue<int>q;
for(int i=1;i<=n;i++){
if(vis[i]) q.push(i);
}
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=h[x];i!=-1;i=nxt[i]){
int y=e[i];
if(lev[y]==0||lev[y]==lev[x]+1){
lev[y]=lev[x]+1;
num[y]+=num[x];
if(!vis[y]){
vis[y]=1;
q.push(y);
}
}
}
}
for(int i=1;i<=n;i++){
if(num[i]==m){
puts("YES");
printf("%d\n",i);
return;
}
}
puts("NO");
return;
}
int main(){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=0;i<m;i++){
int x;
scanf("%d",&x);
vis[x]=1;
lev[x]=1;
num[x]=1;
}
bfs();
return 0;
}
现有一张有向无环图,给出每个点到另一个点的方案数的个位数(且只能从下标小的点到下标大的点),需将该图还原(若两个点能直达输出1,否则输出0)
思路:
两个点 i , j ( i < j ) i,j(i
1、可以直达
2、需要通过其他点才能到达
对于第二种情况,其实无需知道需要经过多少个点才能到达
若 i i i-> j j j的唯一路径为: i i i-> k k k-> a a a-> ⋯ \cdots ⋯-> b b b-> j j j
只需要找到 i i i能够直达的点 k k k,看从点 k k k到点 j j j的方案数有多少种,若其刚好等于从点 i i i到点 j j j的方案数,那么点 i i i肯定不能直达点 j j j,否则说明 i i i和 j j j之间存在一条直达路径。
#include
using namespace std;
const int maxn=2e3+10;
const int INF=0x3f3f3f3f;
typedef long long ll;
const int mod=1e9+7;
int a[550][550];
int mp[550][500];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
string s;
cin>>s;
s=" "+s;
for(int j=1;j<=n;j++){
a[i][j]=s[j]-'0';
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int sum=0;
for(int k=i+1;k<j;k++){//先找出i能够直达的点
if(mp[i][k]) sum+=a[k][j];
}
if(sum%10!=a[i][j]) mp[i][j]=1;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<mp[i][j];
}
cout<<endl;
}
return 0;
}
给出长度为 n n n的数组 a 1 , a 2 , ⋯ , a n a_1,a_2,\cdots,a_n a1,a2,⋯,an
给出 q q q个查询,每次查询给出一个 t t t值,需将数组分段为每一段的和都不超过 t t t,求最少能分成多少段?
思路:
前缀和+二分
先处理出数组的前缀和,再用二分确定分段区间
如果数组的最大值大于 t t t,则不可能将其完全分段
#include
using namespace std;
const int maxn=1e6+10;
const int INF=0x3f3f3f3f;
typedef long long ll;
const int mod=1e9+7;
int a[maxn],sum[maxn];
int ans[maxn];
int main(){
int n;
cin>>n;
int mmax=0;
for(int i=1;i<=n;i++){
cin>>a[i];
mmax=max(mmax,a[i]);
sum[i]=sum[i-1]+a[i];
}
int q;
cin>>q;
for(int i=0;i<q;i++){
int t;
cin>>t;
if(t<mmax) cout<<"Impossible\n";
else if(ans[t]) cout<<ans[t]<<endl;
else{
int l=0;
int cnt=0;
while(l<n){
int num=sum[l]+t;
l=lower_bound(sum+1+l,sum+n+1,num)-sum;//二分寻找下一个区间
if(sum[l]>num) l--;
cnt++;
}
ans[t]=cnt;
cout<<ans[t]<<endl;
}
}
return 0;
}