Problem
T1
我们知道,某数 \(x \bmod 9\) 的值 \(= x\) 各个数位上的数之和 \(\bmod \ 9\) 的值。
于是遍历 \([a,b]\),求出区间中每个数各个数位上的数之和 \(sum\),输出 \(sum \bmod 9\) 即可。
T2
中规中矩的 \(dp\)。
令 \(dp_{i,0}\) 表示第 \(i\) 个数填 \(0\) 时的方案数,\(dp_{i,1}\) 同理。
于是答案即为 \(dp_{i,0}+dp_{i,1}\)。
\(O(n)\) 预处理,转移方程:
然后 \(k\) 次询问每次 \(O(1)\) 回答即可。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=12345;
int n,k;
int dp[100031][2];
signed main(){
cin>>n;
dp[1][0]=dp[1][1]=1;
for(int i=2;i<=100000;i++)
dp[i][0]=(dp[i-1][0]+dp[i-1][1])%MOD,
dp[i][1]=dp[i-1][0]%MOD;
while(n--)
cin>>k,cout<<(!k?0:(dp[k][0]+dp[k][1])%MOD)<<'\n';
return 0;
}
T3
尝试以每个点为根,计算其散播的最小时间。
具体地,我们先对于当前的点向外扩展,然后将扩展到的点的最小时间压入优先队列。
然后:
对于这张图,点 \(x\) 向外扩展到了 \(x1,x2,x3\) 这三个点,分别在 \(1,2,3\) 的单位时间。
那么,为使每个点的时间尽可能少,我们应当将当前时间最大的点放在 \(x1\),次大的放在 \(x2\),最小的放在 \(x3\),这样就满足了上述条件。
于是我们在递归后将优先队列中的点一一取出,按照上述法则更新每个点的时间即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,tot,ans=1e9;
int out[1031],cost[1031];
vector<int> G[2031];
priority_queue<int> pq[1031];
void dfs(int x,int pre){
cost[x]=0;
for(auto i:G[x]){
if(i==pre) continue;
dfs(i,x);
pq[x].push(cost[i]);
}
for(int i=1;!pq[x].empty();i++){
int now=pq[x].top(); pq[x].pop();
cost[x]=max(cost[x],now+i);
}
}
int main(){
cin>>n;
for(int i=2,v;i<=n;i++)
cin>>v,
G[i].push_back(v),G[v].push_back(i);
for(int i=1;i<=n;i++){
dfs(i,i);
int now_ans=-1e9;
for(int j=1;j<=n;j++)
now_ans=max(now_ans,cost[j]);
if(now_ans+1<ans){
ans=now_ans+1;
tot=0;
memset(out,0,sizeof(out));
out[++tot]=i;
}
else if(now_ans+1==ans)
out[++tot]=i;
//cout<<now_ans<<'\n';
}
cout<<ans<<'\n';
for(int i=1;i<=tot;i++) cout<<out[i]<<' ';
return 0;
}
T4
显然速度是具有单调性的,因此考虑二分答案。
check
函数的设计:
对于我们二分的速度值 \(k\),我们令图中一条边 \(e=(i,j)\) 的边权为 \(p_{i,j}-k \times t_{i,j}\)(即实际距离减理想距离),然后再这张图上跑 SPFA 最短路。
求出 \(dis\) 数组(单源最短路)后,若 \(dis_n \ge 0\),则说明还有某些路没跑完,速度值太小,令 \(l=mid\),否则令 \(r=mid\)。
若图存在负环,则速度变成无限大都跑不出去,于是一直令 \(l=mid\) 即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int p[131][131],t[131][131];
double w[131][131],dis[131];
int cnt[131];
bool vis[131];
bool spfa(){
queue<int> q;
memset(dis,-0x3f3f3f3f,sizeof(dis));
memset(cnt,0,sizeof(cnt));
memset(vis,0,sizeof(vis));
q.push(1);
dis[1]=0,vis[1]=cnt[1]=1;
while(!q.empty()){
int u=q.front(); q.pop(),vis[u]=0;
for(int v=1;v<=n;v++){
if(p[u][v]&&dis[v]<dis[u]+w[u][v]){
dis[v]=dis[u]+w[u][v];
if(!vis[v]){
cnt[v]++;
if(cnt[v]>n) return 1;
vis[v]=1;
q.push(v);
}
}
}
}
return dis[n]>=0;
}
bool check(double x){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
w[i][j]=p[i][j]-t[i][j]*x;
return spfa();
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>p[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>t[i][j];
double l=0.0,r=10000.0,eps=0.0001;
while(l+eps<r){
double mid=(l+r)/2.0;
if(check(mid)) l=mid;
else r=mid;
}
cout<<setprecision(3)<<fixed<<l;
return 0;
}