• 20210812dp模拟赛


    考的是不太擅长的DP……

    赛时

    题目有错误!

    导致用了很长时间才看全题目……

    四道题都不太会……

    赛时还是写上了一些暴力,拿到了一些分数……

    见赛后吧……

    赛后

    四道赛题,订正了很长时间。

    T1

    Lecture

    明显是数位dp。但是考场上没写出来

    与一般的dp不同,发现从最高位到最低位很难维护。

    想到逆向,从最低位到最高位。

    问题变得好解决:两个bool判断当前后缀是否为倍数此数是否可选取(是否均为0).

    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    const int INF = 0x3f3f3f3f , N = 1e3+5 , M = 1e2+5;
    typedef long long ll;
    typedef unsigned long long ull;
    inline ll read(){
    	ll ret = 0 ;char ch = ' ' , c = getchar();
    	while(!(c >= '0' && c <= '9'))ch = c , c = getchar();
    	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
    	return ch == '-' ? -ret : ret;
    }
    int n,k,mod;
    int dp[N][M][2],Pow[N];
    
    int dfs(int pos,int num,bool jud,bool zero){
        if(pos > n)return jud;
    	if(!zero && dp[pos][num][jud] != -1)return dp[pos][num][jud];
    	int ans = 0;
    	for(int i = 0 ; i <= 9 ; i ++){
    		if(pos == n && !i)continue;
    		int nnum = (i * Pow[pos] + num) % k,
    			nzero = zero && !i;
    		(ans += dfs(pos+1 , nnum , jud || (!nnum && !nzero),nzero)) %= mod;
    	}
    	if(!zero)dp[pos][num][jud] = ans;
    	return ans;
    }
    signed main(){
    	memset(dp,-1,sizeof(dp));
    	n = read() , k = read() , mod = read();
    	Pow[1] = 1;
    	for(int i = 2 ; i <= n ; i ++)
    		Pow[i] = (Pow[i-1] * 10) % k;
    	printf("%d",dfs(1,0,0,1));
    }
    

    T2

    CF601C Kleofáš and the n-thlon

    一个期望dp啦

    dp[i][j]表示前(i)个人获得(j)分数的概率,处理期望即可。

    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    const int INF = 0x3f3f3f3f , N = 1e2+5 , M = 1e3+5;
    typedef long long ll;
    typedef unsigned long long ull;
    inline ll read(){
    	ll ret = 0 ;char ch = ' ' , c = getchar();
    	while(!(c >= '0' && c <= '9'))ch = c , c = getchar();
    	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
    	return ch == '-' ? -ret : ret;
    }
    int n,m;
    int a[N],sum;
    double dp[N][M*N],s[M*N];
    double ans;
    signed main(){
    //	fo("nthlon");
    	n = read() , m = read();
    	for(int i = 1 ; i <= n ; i ++)
    		a[i] = read() , 
    		sum += a[i];
    	for(int i = 1 ; i <= m ; i ++){
    		if(i != a[1])
    			dp[1][i] = 1.0 / (m-1);
    	}
    	for(int i = 2 ; i <= n ; i ++){
    		for(int j = 1 ; j <= i*m ; j ++)
    			s[j] = s[j-1] + dp[i-1][j];
    		for(int j = i ; j <= i*m ; j ++){
    			if(j <= m+1) dp[i][j] = s[j-1] - dp[i-1][j-a[i]] * (1 <= j-a[i]);
    			else 		 dp[i][j] = s[j-1] - s[j-m-1] - dp[i-1][j-a[i]] * (j-m <= j-a[i]);
    			dp[i][j] /= (m-1);
    //			for(int k = 1 ; k <= min(j-1,m) ; k ++)
    //				if(k != a[i])
    //					dp[i][j] += dp[i-1][j-k]/(m-1),
    //			printf("  dp[%d][%d] = s[%d][%d](%.3lf) - s[%d][%d](%.3lf)
    ",i,j,i-1,j-1,s[i-1][j-1],i-1,max(1,j-m)-1,s[i-1][max(1,j-m)-1]);
    		}
    	}
    //	for(int i = 1 ; i <= n ; i ++)
    //		for(int j = 1 ; j <= i*m ; j ++)
    //			printf("  dp[%d][%d] = %lf
    ",i,j,dp[i][j]);
    	for(int i = 1 ; i < sum ; i ++)
    		ans += dp[n][i];
    	printf("%.15lf",ans * (m-1) + 1 );
    	
    	return 0;
    }
    /*
    2 2 1000
    */
    

    T3

    Branch Assignment

    跑两遍dij,找出(i o b+1)(b+1 o i)的最短路。设(dis[i])为二者之和。

    则接下来的任务就是将dis[1],dis[2],...dis[b]分成s 组,每组的代价为该组内dis 之和*(该组内dis 元素个数-1),目标是最小化所有组的代价之和。

    便是排序之后,运用分段dp的思想进行转移。

    在最优解中,dis 从小到大依次划分所得到的段的长度一定是单调不增的,则上述DP 转移中k 的最优取
    值一定在([i-dfrac ij,i))之间,于是总转移复杂度就是(O(n²(1/1+1/2+1/3+...+1/n)) =O(n²logn)),足以通过本题。

    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    const int INF = 0x3f3f3f3f,N = 5e3+5 , M = 5e4+5;
    typedef long long ll;
    typedef unsigned long long ull;
    inline ll read(){
    	ll ret = 0 ;char ch = ' ' , c = getchar();
    	while(!(c >= '0' && c <= '9'))ch = c , c = getchar();
    	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
    	return ch == '-' ? -ret : ret;
    }
    int n,b,s,m;
    int ecnt1 = -1 ,ecnt2 = -1 , head1[N] , head2[N];
    struct Edge{int to,nxt,w;}e1[M],e2[M];
    inline void add_edge1(int u,int v,int w){
    	e1[++ecnt1] = (Edge){v,head1[u],w};
    	head1[u] = ecnt1;
    }
    inline void add_edge2(int u,int v,int w){
    	e2[++ecnt2] = (Edge){v,head2[u],w};
    	head2[u] = ecnt2;
    }
    int dis1[N],dis2[N];ll dis[N];bool vis1[N],vis2[N];
    typedef pair<int,int> pr;
    priority_queue<pr,vector<pr>,greater<pr> >q; 
    void dij1(int s){
    	while(!q.empty())q.pop();
    	memset(dis1,0x3f,sizeof(dis1));
    	memset(vis1,0,sizeof(vis1));
    	dis1[s] = 0 ; q.push(make_pair(0,s));
    	while(!q.empty()){
    		int u = q.top().second;q.pop();
    		if(vis1[u])continue;
    		vis1[u] = 1;
    		for(int i = head1[u] ; ~i ; i = e1[i].nxt){
    			int v = e1[i].to , w = e1[i].w;
    			if(dis1[v] > dis1[u] + e1[i].w)
    				dis1[v] = dis1[u] + e1[i].w,
    				q.push(make_pair(dis1[v],v));
    		}
    	}
    }
    void dij2(int s){
    	while(!q.empty())q.pop();
    	memset(dis2,0x3f,sizeof(dis2));
    	memset(vis2,0,sizeof(vis2));
    	dis2[s] = 0 ; q.push(make_pair(0,s));
    	while(!q.empty()){
    		int u = q.top().second;q.pop();
    		if(vis2[u])continue;
    		vis2[u] = 1;
    		for(int i = head2[u] ; ~i ; i = e2[i].nxt){
    			int v = e2[i].to , w = e2[i].w;
    			if(dis2[v] > dis2[u] + e2[i].w)
    				dis2[v] = dis2[u] + e2[i].w,
    				q.push(make_pair(dis2[v],v));
    		}
    	}
    }
    ll dp[N][N],sum[N];
    void work(){
    //	fo("assignment");
    	memset(head1,-1,sizeof(head1));memset(head2,-1,sizeof(head2));
    	ecnt1 = ecnt2 = -1;
    	for(int i = 1 ; i <= m ; i ++){
    		int u = read() , v = read() , w = read();
    		add_edge1(u,v,w);
    		add_edge2(v,u,w);
    	}
    	dij1(b+1);dij2(b+1);
    	for(int i = 1 ; i <= b ; i ++)
    //		printf("%d : %d,%d
    ",i,dis1[i],dis2[i]),
    		dis[i] = dis1[i] + dis2[i];
    	sort(dis+1,dis+b+1);
    	for(int i = 1 ; i <= b ; i ++)
    		sum[i] = sum[i-1] + dis[i];
    //	memset(dp,0x3f,sizeof(dp));
    	dp[0][0] = 0;
    	for(int i = 1 ; i <= b ; i ++){
    		dp[i][0]= 1LL * INF * INF;
    		for(int j = 1 ; j <= min(i,s) ; j ++){
    			dp[i][j] = 2e15;
    			for(int k = i-i/j ; k <= i ; k ++)
    			dp[i][j] = min(dp[i][j],dp[k][j-1] + (sum[i]-sum[k]) * (i-k-1));
    //			printf("  dp[%d][%d] = min(dp[%d][%d](%lld) + sum[%d,%d](%lld) * (%d-%d-1)))
    ",i,j,k,j-1,dp[k][j-1],i,k,sum[i]-sum[k],i,k);
    		}
    	} 
    //	for(int i = 1 ; i <= b ; i ++)
    //		for(int j = 1 ; j <= min(i,s) ; j ++)
    //			printf("dp[%d][%d] = %lld
    ",i,j,dp[i][j]);
    	printf("%lld
    ",dp[b][s]);
    }
    signed main(){
    	while(scanf("%d %d %d %d",&n,&b,&s,&m) != EOF)
    		work();
    	return 0;
    }
    
  • 相关阅读:
    6月11日 python学习总结 框架理论
    6月7日 python 复习 collections
    6月6日 python复习 面向对象
    6月6日 python学习总结 jQuery (三)
    6月5日 python复习 模块
    6月5日 python学习总结 jQuery (二)
    6月4日 python学习总结 装饰器复习
    Redis源码分析(五)--- sparkline微线图
    Redis源码分析(六)--- ziplist压缩列表
    Redis源码分析(六)--- ziplist压缩列表
  • 原文地址:https://www.cnblogs.com/Shinomiya/p/15135604.html
Copyright © 2020-2023  润新知