https://file.floj.tech/export/1299
t1
按时间排序,发现如果后头的人比前头的人楼层高则前头的人莫得用,后面的人送上去时这个人必上去了。
然后就可以得到一个楼层单调递减的序列,考虑f[i]表示前i个人送完最短时间。f[i]=max(f[j],t[i])+2*h[j+1],对f[j]<t[i]的最大的j用t[i]转移,f[j]>t[i]的用单调队列维护最小值即可。
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int n,dao,top,f[N],que[N];
struct pigu
{
int t,h;
}a[N],st[N];
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
inline bool cmp(pigu x,pigu y)
{
return x.t<y.t;
}
signed main()
{
// freopen("elevator.in","r",stdin);
// freopen("elevator.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i].t=read(),a[i].h=read();
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
while(top&&st[top].h<=a[i].h) top--;
st[++top]=a[i];
}
int head=1,tail=0;
for(int i=1;i<=top;i++)
{
while(dao<i-1&&f[dao+1]<=st[i].t) dao++;
f[i]=st[i].t+st[dao+1].h*2;
while(head<=tail&&f[que[head]]<=st[i].t) head++;
if(head<=tail) f[i]=min(f[i],f[que[head]]+2*st[que[head]+1].h);
while(head<=tail&&f[i]+2*st[i+1].h<=f[que[tail]]+2*st[que[tail]+1].h) tail--;
que[++tail]=i;
}
cout<<f[top];
return 0;
}
t2
矩阵快速幂。
当T=0时就是求<=k的路径数,否则就是求疲劳值*路径数。
用二项式定理将其拆开,y=1,构造(T+2)*n*(T+2)*n的矩阵即可。
ans[i][j]表示从i出发走当前步数到j%n这个地方并且疲劳值的参数T=j/n时,路径数*疲劳值。
转移矩阵大概kai[i][j]即为A[i%n][j%n]*C[j/n][i/n]。
代码如下:
#include<bits/stdc++.h>
#define ll long long
#pragma GCC optimize("Ofast")
using namespace std;
const int N=492;
const int mo=998244353;
ll n,k,q,T,m,kais[75][75],C[9][9];
struct matrix
{
ll ma[N][N];
matrix operator *(const matrix &x) const
{
matrix z;memset(z.ma,0,sizeof(z.ma));
for(int i=1;i<=m;++i)
for(int k=1;k<=m;++k)if(ma[i][k])
for(int j=1;j<=m;++j)if(x.ma[k][j])
(z.ma[i][j]+=ma[i][k]*x.ma[k][j])%=mo;
return z;
}
}kai,ans;
inline ll read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
signed main()
{
// freopen("road.in","r",stdin);
//freopen("road.out","w",stdout);
n=read();k=read();q=read();T=read();m=(T+2)*n;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) kais[i][j]=read();
for(int i=0;i<=T;i++) C[i][0]=1;
for(int i=1;i<=T;i++)
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1]);
for(int i=0;i<=T;i++)
for(int j=i;j<=T;j++)
for(int l=1;l<=n;l++)
for(int o=1;o<=n;o++)
kai.ma[i*n+l][j*n+o]=C[j][i]*kais[l][o]%mo;
for(int i=1;i<=n;i++) ans.ma[i][i]=1;
for(int i=1;i<=n;i++) kai.ma[T*n+i][T*n+n+i]=kai.ma[n*(T+1)+i][n*(T+1)+i]=1;
while(k){if(k&1)ans=ans*kai;kai=kai*kai;k>>=1;}
for(int i=1,x,y;i<=q;i++)
{
x=read();y=read();
cout<<ans.ma[x][n*(T+1)+y]<<"
";
}
}
t3
发现f就是一个k+1的多项式,所以g是k+2多项式,h是k+3多项式,使用拉格朗日插值求出前k+1,k+2,k+3项,就可以求第n项了。
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1105;
int T,k,f1,f2,f3,n,a,d,mo,h[N],g[N],f[N],inv[N],pre[N],suf[N];
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
inline int query(int * s,int len,int qiu)
{
int ans=0;
if(qiu<=len) return s[qiu];
for(int i=0;i<=len;i++)
pre[i]=1ll*(qiu-i)*(i==0?1:pre[i-1])%mo;
for(int i=len;i>=0;i--)
suf[i]=1ll*(qiu-i)*(i==len?1:suf[i+1])%mo;
for(int i=0;i<=len;i++)
{
int add=1ll*s[i]*(i==0?1:pre[i-1])%mo*(i==len?1:suf[i+1])%mo;
add=1ll*add*inv[i]%mo*inv[len-i]%mo*(len-i&1?-1:1);
ans=(ans+add)%mo+mo;
ans%=mo;
}
return ans;
}
int qpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=1ll*a*a%mo)
if(b&1)ans=1ll*ans*a%mo;
return ans;
}
signed main()
{
T=read();
while(T--)
{
k=read();n=read();a=read();d=read();mo=read();
f1=k+1;f2=k+2;f3=k+3;inv[0]=1;
for(int i=1;i<=f3;++i)inv[i]=i==1?1:1ll*(mo-mo/i)*inv[mo%i]%mo;
for(int i=1;i<=f3;++i)inv[i]=1ll*inv[i-1]*inv[i]%mo;
for(int i=1;i<=f1;i++)
f[i]=(f[i-1]+qpow(i,k))%mo;
cout<<query(f,f1,n)<<" ";
for(int i=1;i<=f2;i++) g[i]=(g[i-1]+query(f,f1,i))%mo;
cout<<query(g,f2,n)<<" ";
for(int i=0;i<=f3;i++)
h[i]=query(g,f2,(1ll*i*d+a)%mo)+(i==0?0:h[i-1]),h[i]%=mo;
cout<<query(h,f3,n)<<"
";
}
}