NOI Online #2 入门组
未了
题意:
一座高\(n\)米的山,每秒爬\(v\)米,有\(n\)个魔法,第\(i\)个魔法可以让你爬到\(a_i\)米时传送回山脚,\(m\)次询问,每次问最少用多少个魔法,才能让爬山时间大于\(t_i\)
\(n,m\leq 10^5\)
题解:
\(a_i\)从大到小排序,前缀和二分。\(O(nlogn)\)
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=3e5+10;
int n,m,len,v;
int a[N],s[N];
inline void main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,len,v;
cin>>n>>len>>v;
for(int i=1;i<=n;++i) cin>>a[i];
sort(a+1,a+n+1);
for(int i=1;i<=n;++i) s[i]=s[i-1]+a[n-i+1];
cin>>m;
for(int i=1;i<=m;++i)
{
int x;cin>>x;
x=x*v;
x-=len;
if(x>=s[n]) cout<<"-1\n";
else
{
int t=upper_bound(s+0,s+n+1,x)-s;
cout<<t<<'\n';
}
}
}
}
signed main()
{
red::main();
return 0;
}
荆轲刺秦王
题意:
\(n*m\)的地图上荆轲要去刺秦王,荆轲每秒可以向周围八个格子移动一步,地图上有卫兵,可以发现曼哈顿距离小于\(a_{i,j}\)范围内的格子的入侵者。
荆轲可以用技能:
\(1.\)隐身,一秒内不被卫兵发现
\(2.\)瞬移,朝上下左右某个方向移动\(d\)格
分别能用\(c1,c2\)次
问荆轲最短几步内能刺杀秦王,步数最短的情况下,使用两种技能总次数最少,前面的前提下,隐身次数最少。
\(n,m,d,a_{i,j}\leq 350,c1,c2\leq 15\)
题解:
用差分处理曼哈顿距离,预处理出哪些格子必须隐身才能走过去。
然后就是裸\(bfs\)
\(O(n*m^2+n*m*c1*c2)\)
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=350+10,inf=2e9;
int a[N][N],cf[N][N];
int n,m,c1,c2,d;
int stx,sty,edx,edy;
struct node
{
int x,y,s1,s2,dis;
};
queue<node> q;
bool vis[355][355][16][16];
int dx[8]={-1,-1,0,1,1,1,0,-1},dy[8]={0,1,1,1,0,-1,-1,-1};
int ans1,ans2,ans3;
inline void bfs()
{
q.push((node){stx,sty,0,0,0});
ans1=inf;
while(!q.empty())
{
node now=q.front();
q.pop();
int x=now.x,y=now.y,s1=now.s1,s2=now.s2,dis=now.dis;
//cout<<x<<' '<<y<<' '<<dis<<endl;
if(vis[x][y][s1][s2]) continue;
vis[x][y][s1][s2]=1;
if(x==edx&&y==edy)
{
if(dis<ans1||(dis==ans1&&s1+s2<ans2+ans3)||(dis==ans1&&s1+s2==ans2+ans3&&s1<ans2))
ans1=dis,ans2=s1,ans3=s2;
}
if(dis>ans1) break;
for(int k=0;k<8;++k)
{
int tx=x+dx[k],ty=y+dy[k],ts1=s1,ts2=s2,tdis=dis+1;
//cout<<tx<<' '<<ty<<"!!"<<endl;
if(a[tx][ty]==-1||tx<1||tx>n||ty<1||ty>m) continue;
ts1+=a[tx][ty];
if(ts1>c1||ts2>c2) continue;
if(vis[tx][ty][ts1][ts2]) continue;
q.push((node){tx,ty,ts1,ts2,tdis});
}
for(int k=0;k<8;k+=2)
{
int tx=x+dx[k]*d,ty=y+dy[k]*d,ts1=s1,ts2=s2+1,tdis=dis+1;
if(a[tx][ty]==-1||tx<1||tx>n||ty<1||ty>m) continue;
ts1+=a[tx][ty];
if(ts1>c1||ts2>c2) continue;
if(vis[tx][ty][ts1][ts2]) continue;
q.push((node){tx,ty,ts1,ts2,tdis});
}
}
if(ans1==inf) cout<<"-1\n";
else cout<<ans1<<' '<<ans2<<' '<<ans3<<'\n';
}
inline void main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m>>c1>>c2>>d;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
string ch;cin>>ch;
if(ch[0]=='S') stx=i,sty=j;
if(ch[0]=='T') edx=i,edy=j;
if(ch[0]>='0'&&ch[0]<='9')
{
int num=0;
for(int k=0;k<ch.length();++k) num=num*10+ch[k]-'0';
--num;
a[i][j]=-1;
for(int k=i-num,l=0;k<=i;++k,++l)
{
if(k>=1)
{
++cf[k][max(1ll,j-l)];
if(j+l+1<=m) --cf[k][j+l+1];
}
}
for(int k=i+1,l=num-1;k<=min(n,i+num);++k,--l)
{
++cf[k][max(1ll,j-l)];
if(j+l+1<=m) --cf[k][j+l+1];
}
}
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
cf[i][j]+=cf[i][j-1];
if(cf[i][j]>0&&!a[i][j]) a[i][j]=1;
//cout<<a[i][j]<<" \n"[j==m];
}
}
bfs();
}
}
signed main()
{
red::main();
return 0;
}
建设城市
题意:
有\(2n\)栋楼,每栋楼高是\(1\sim m\),要求前\(n\)栋楼高度不下降,后\(n\)栋楼高度不上升,且编号为\(x,y\)的楼高度相等,求方案数。
\(n,m\leq 10^5\)
以\(x\leq n,y>n\)为例:
枚举\(x,y\)的高度\(k\)
则\(ans=\sum_{k=1}^mf(x-1,k)*f(n-x,m-k+1)*f(y-n-1,m-k+1)*f(2*n-y,k)\)
其中\(f(n,m)\)表示\(n\)栋楼,取值范围是\(1\sim m\),且不下降的方案数。
这个方案数其实就是\(n\)个物品分成\(m\)组,可以有空组的方案数。
\(O(2*n+m)\)
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=5e5+10,mod=998244353,inf=2e9;
int n,m,x,y;
int fac[N],inv[N];
inline int fast(int x,int k)
{
int ret=1;
while(k)
{
if(k&1) ret=ret*x%mod;
x=x*x%mod;
k>>=1;
}
return ret;
}
inline int C(int n,int m)
{
if(n<m) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
inline int cb(int n,int m)
{
//cout<<n<<' '<<m<<' '<<C(n+m-1,m-1)<<"!!"<<endl;
//x1+x2+…+xm=n
//
return C(n+m-1,m-1);
}
inline void work1()
{
int ans=0;
for(int k=1;k<=m;++k)
{
int tmp=cb(x-1,k)*cb(n-y,m-k+1)%mod*cb(n,m)%mod;
ans=(ans+tmp)%mod;
}
cout<<ans<<'\n';
}
inline void work2()
{
int ans=0;
for(int k=1;k<=m;++k)
{
int tmp=cb(x-1,k)*cb(n-x,m-k+1)%mod*cb(2*n-y,k)%mod*cb(y-n-1,m-k+1)%mod;
//cout<<k<<' '<<cb(x-1,k)<<' '<<cb(n-x,m-k+1)<<' '<<cb(y-n-1,m-k+1)<<' '<<cb(2*n-y,k)<<endl;
ans=(ans+tmp)%mod;
}
cout<<ans<<'\n';
}
inline void init(int n)
{
fac[0]=inv[0]=1;
for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%mod;
inv[n]=fast(fac[n],mod-2);
for(int i=n-1;i>=1;--i) inv[i]=inv[i+1]*(i+1)%mod;
}
inline void main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>m>>n>>x>>y;
init(2*n+m);
if(x>y) swap(x,y);
if(x>n)
{
x=2*n-x+1,y=2*n-y+1;
swap(x,y);
}
if(y<=n) work1();
else work2();
}
}
signed main()
{
red::main();
return 0;
}
/*
3 2 3 4
*/