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(但是鸽了). 的确是要多思考.

posted @ 2021-07-05 16:26  xyangh  阅读(170)  评论(0)    收藏  举报