其他分享
首页 > 其他分享> > Educational Codeforces Round 129 (Rated for Div. 2)

Educational Codeforces Round 129 (Rated for Div. 2)

作者:互联网

真,自闭场
C题已经忘记是什么了,记得一开始的做法不知道错哪了,最后改了个做法才过
D原本一直在想有什么数论上的性质和结论,一直局限于乘的那个数的选择,没有从因数的角度考虑,于是自闭
F最后看了下感觉可做,后来发现确实不难

D

其实本质是从搜索的角度出发,然后考虑状态的数量:只要发现每个状态都是x与一些小于10的数相乘,就可以直接记录乘的数的2,3,5,7的次幂,然后直接DP即可。
原本写了个四维DP,觉得代码量不像1700的题,后来看题解发现BFS会短很多(甚至不需要记录次幂,就直接单位边权图的最短路即可)
因为可DP的充要条件是状态转移满足拓扑序,所以在一些形式上不是DAG但本质是DAG,但直接用数组又比较麻烦的题上,可以直接BFS会好写很多!
(当时其实有尝试写个记忆化搜索,但心态较崩且觉得不对就没调完,其实是可以过的...)

垃圾DP版代码

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N=65;
void Min(int& a,int b){
	a=min(a,b);
}
ll n,m,x;
int a[5]={0,2,3,5,7},b[5],d[11][5];
int f[N][N][N][N];
int main()
{
	cin>>n>>x;
	m=1; n--;
	while(n--) m*=10;
	for(int i=1;i<=4;i++) b[i]=log(m/x)/log(a[i])+3;
	d[2][1]=d[3][2]=d[5][3]=d[6][1]=d[6][2]=d[7][4]=1;
	d[4][1]=d[9][2]=2;
	//!!! a[2]=3->d[9][2]!!!
	d[8][1]=3;
	memset(f,0x3f,sizeof(f));
	f[0][0][0][0]=0;
	int c[5]={0},ans=1e9;
	for(c[1]=0;c[1]<=b[1];c[1]++){
		for(c[2]=0;c[2]<=b[2];c[2]++){
			for(c[3]=0;c[3]<=b[3];c[3]++){
				for(c[4]=0;c[4]<=b[4];c[4]++){
					if(f[c[1]][c[2]][c[3]][c[4]]>1e9) continue;
					ll s=x;
					bool p=(s>=m);
					for(int u=1;u<=4;u++){
						for(int v=1;v<=c[u];v++){
							if(s>m/a[u]){
								p=1;
								break;
							}
							s*=a[u];
						}
						if(p) break;
					}
					if(p || s>=m){
						ans=min(ans,f[c[1]][c[2]][c[3]][c[4]]);
						continue;
					}
					//printf("s=%lld f=%d\n",s,f[c[1]][c[2]][c[3]][c[4]]);
					//for(int i=1;i<=4;i++) cout<<c[i]<<" "; puts("");
					while(s){
						int t=s%10;
						Min(f[c[1]+d[t][1]][c[2]+d[t][2]][c[3]+d[t][3]][c[4]+d[t][4]],f[c[1]][c[2]][c[3]][c[4]]+1);
						//cout<<"t="<<t<<endl;
						s/=10;
					}
				}
			}
		}
	}
	if(ans>=1e9) puts("-1");
	else cout<<ans<<endl;
	return 0;
}

F

一开始先想每条边的贡献,然后是一个类似换根DP的问题,可能需要线段树合并维护,感觉不太友善。
然后想到,边权相同的边的贡献一起考虑,这就是一个类似于虚数的东西,建出来之后直接计算即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
int n,hd[N],to[N<<1],nx[N<<1],wl[N<<1],tt;
void add(int u,int v,int w){
	nx[++tt]=hd[u];
	to[hd[u]=tt]=v;
	wl[tt]=w;
}
int fa[N],fx[N],dn[N],sz[N],ct;
void dfs(int u){
	sz[u]=1;
	dn[u]=++ct;
	for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa[u]){
		int v=to[e];
		fa[v]=u; fx[v]=wl[e];
		dfs(v);
		sz[u]+=sz[v];
	}
}
bool cmp(int x,int y){
	return dn[x]<dn[y];
}
vector<int>h[N];
int f[N],g[N],q[N];
ll ans;
int main()
{
	cin>>n;
	for(int u,v,x,i=1;i<n;i++) scanf("%d%d%d",&u,&v,&x),add(u,v,x),add(v,u,x);
	dfs(1);
	for(int i=2;i<=n;i++) h[fx[i]].push_back(i);
	for(int i=1;i<=n;i++){
		int z=h[i].size();
		if(!z) continue;
		sort(h[i].begin(),h[i].end(),cmp);
		//printf("i=%d z=%d\n",i,z);
		g[z]=n;
		f[z]=0;
		q[0]=z;
		int t=0;
		for(int j=0;j<z;j++){
			int u=h[i][j];
			//cout<<"u="<<u<<endl;
			while(t && dn[u]>=dn[h[i][q[t]]]+sz[h[i][q[t]]]) t--;
			f[j]=q[t];
			g[j]=sz[u];
			g[q[t]]-=g[j];
			q[++t]=j;
		}
		for(int i=0;i<z;i++) ans+=1ll*g[i]*g[f[i]];
	}
	cout<<ans<<endl;
	return 0;
}

标签:Educational,Rated,int,ll,Codeforces,long,--,ans,DP
来源: https://www.cnblogs.com/szsz/p/16472909.html