abc 208
D - Shortest Path Queries 2
给出一张有 \(n\) 个节点 \(m\) 条边的带权有向图.
定义 \(f(s,t,k)\) 表示从点 \(s\) 到点 \(k\),除了只允许经过点 \(1\) 到点 \(k\) 时的最小代价.
求 \(\sum\limits_1^n\sum\limits_1^n\sum\limits_1^n f(s,t,k)\).
\(1\leq n\leq 400,1\leq m\leq n(n-1)\)
首先枚举起点 \(s\) 是跑不掉的. 考虑依次加入 \(1\) 到 \(n\) 在上一次跑完的图上做 dijkstra ,以此保证时间复杂度.
时间复杂度: \(O((n+m)logm+n^3)\)
空间复杂度: \(O(n)\)
第一次提交: Accept
my code
#include<bits/stdc++.h>
using namespace std;
const long long inf=1e18+10;
int n,m;
vector<pair<int,int> >g[410];
long long ans=0;
long long dist[410];
priority_queue<pair<long long,int> >Q;
void solve(int s){
for(int i=0;i<n;i++)dist[i]=inf;
while(!Q.empty())Q.pop();
dist[s]=0;
Q.push(make_pair(-dist[s],s));
for(int i=0;i<n;i++){
if(dist[i]!=inf)Q.push(make_pair(-dist[i],i));
while(!Q.empty()){
int x=Q.top().second,val=-Q.top().first;Q.pop();
if(val>dist[x])continue;
for(int j=0;j<(int)g[x].size();j++){
int to=g[x][j].first,cost=g[x][j].second;
if(dist[to]>dist[x]+cost){
dist[to]=dist[x]+cost;
if(to<=i)Q.push(make_pair(-dist[to],to));
}
}
}
for(int j=0;j<n;j++)if(dist[j]!=inf)ans+=dist[j];
/* for(int j=0;j<n;j++)if(dist[j]!=inf){
cout<<s<<","<<j<<","<<i<<","<<dist[j]<<endl;
}
*/
}
}
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){
int u,v,cost;
cin>>u>>v>>cost;
u--;v--;
g[u].push_back(make_pair(v,cost));
}
for(int s=0;s<n;s++)solve(s);
cout<<ans<<endl;
return 0;
}
/*inline? ll or int? size? min max?*/
E - Digit Products
求不超过 \(n\) 的正整数中数位的乘积不超过 \(m\) 的数的个数.
\(1\leq n\leq 10^{18},1\leq m\leq 10^9\).
分成两类:
1.没有 \(0\) .
我写了dfs跑了一下不超过 \(10^9\) 可以由 \(1\) 到 \(9\) 相乘得到的有5000多个. 所以可以用map存储.
2.有 \(0\) .
多写一维记录是否存在 \(0\) 即可.
时间复杂度: \(...\)
空间复杂度: \(...\)
第一次提交: Accept
my code
#include<bits/stdc++.h>
using namespace std;
int k;
long long n;
map<int,long long>dp[20][2];
int a[20],d=0;
long long f[20][2][2];
long long ans=0;
int main(){
cin>>n>>k;
while(n>0){
a[d++]=n%10;
n/=10;
}
reverse(a,a+d);
for(int i=1;i<10;i++){
if(i<a[0])dp[0][0][i]++;
if(i==a[0])dp[0][1][i]++;
}
for(int i=0;i+1<d;i++){
for(int j=1;j<10;j++)dp[i+1][0][j]++;
for(map<int,long long>::iterator it=dp[i][0].begin();it!=dp[i][0].end();it++){
if(it->first>k)continue;
for(int j=1;j<10;j++){
if(1ll*it->first*j>k)continue;
dp[i+1][0][it->first*j]+=dp[i][0][it->first];
}
}
for(map<int,long long>::iterator it=dp[i][1].begin();it!=dp[i][1].end();it++){
if(it->first>k)continue;
for(int j=1;j<=a[i+1];j++){
if(1ll*it->first*j>k)continue;
dp[i+1][j==a[i+1]][it->first*j]+=dp[i][1][it->first];
}
}
}
for(map<int,long long>::iterator it=dp[d-1][0].begin();it!=dp[d-1][0].end();it++)
if(it->first<=k)ans+=it->second;
for(map<int,long long>::iterator it=dp[d-1][1].begin();it!=dp[d-1][1].end();it++)
if(it->first<=k)ans+=it->second;
// cout<<ans<<endl;
// for(int i=0;i<d;i++)cout<<a[i];cout<<endl;
for(int i=1;i<10;i++){
if(i<a[0])f[0][0][0]++;
if(i==a[0])f[0][1][0]++;
}
for(int i=0;i+1<d;i++){
for(int j=1;j<10;j++)f[i+1][0][0]++;
for(int k=0;k<2;k++){
for(int j=0;j<10;j++)f[i+1][0][k|(j==0)]+=f[i][0][k];
for(int j=0;j<=a[i+1];j++)f[i+1][j==a[i+1]][k|(j==0)]+=f[i][1][k];
}
}
ans+=f[d-1][0][1]+f[d-1][1][1];
cout<<ans<<endl;
return 0;
}
/*inline? ll or int? size? min max?*/
F - Cumulative Sum
不会做... 听说要用到拉格朗日差值. 不会不会,溜了. 以后再来补……
小结
这次abc是我打过排名最高的一次,rating到达了1766(the highest). 再接再厉. 但也有运气的成分. 前几天正好想过和d题思路相似的zab,和e题思路相似的topcoder题,productandsum(但是鸽了). 的确是要多思考.

浙公网安备 33010602011771号