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
*/