zoukankan      html  css  js  c++  java
  • Codeforces Round #677 (Div. 3)

    F. Zero Remainder Sum

    题意

    给定一个 (n imes m) 的矩阵,你可以在每一行选择不多于 (frac{n}{2}) 个元素, 使得整体选择的元素的和模 (k) 为0, 并且和越好。

    [1 leq n, m, k leq 70 ]

    [1 leq a_{i j} leq 70 ]

    分析

    然后一般情况是第j个数字从j-1的对应转移过来,类似背包。但是这题这么做的话对于模数r的转移对应的要求的是(x%k+a[i][j]%k)%k=r的这个x。

    方便一点的话转化成顺推。即考虑第j+1个数字选还是不选。

    对于第i行,第j + 1个数字
    1、选择第j + 1个数字 dp[i][j + 1][l][(r + a[i][j + 1]) % k] = dp[i][j][l - 1][r] + a[i][j+1];
    2、不选择第j + 1个数字 dp[i][j + 1][l][r] = dp[i][j][l][r];

    同时这个题注意上下层的关系也要转移过来,因为下一层的状态选择需要上一层的决策。

    然后每次更新下一层的第0位,就表示上一层模数为r时的最大值

    dp[i + 1][0][0][r] = max(dp[i][j + 1][l][r], dp[i + 1][0][0][r]);

    答案就是 dp[n + 1][0][0][0] : 第n+1行,第0位,取0个数字,模数为0的总和

    代码

    inline int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int maxn=80;
    int dp[maxn][maxn][maxn][maxn];
    int a[maxn][maxn];
    main(void)
    {
    	int n=read();
    	int m=read();
    	int k=read();
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    	{
    		a[i][j]=read();
    	}
    	
      	memset(dp,-1,sizeof(dp));
      	dp[1][0][0][0]=0;
    
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=0;j<m;j++)
    		{
    			for(int cnt=0;cnt<=min(j+1,m/2);cnt++)
    			{
    				for(int p=0;p<=k-1;p++)
    				{
    					dp[i][j+1][cnt][p]=max(dp[i][j+1][cnt][p],dp[i][j][cnt][p]);
    					if(cnt>=1&&dp[i][j][cnt-1][p]!=-1)
    					{
    						dp[i][j+1][cnt][(p+a[i][j+1])%k]=max(dp[i][j+1][cnt][(p+a[i][j+1])%k],dp[i][j][cnt-1][p]+a[i][j+1]);
    					} 
    				}
    				for(int p=0;p<k;p++)
    				dp[i+1][0][0][p]=max(dp[i+1][0][0][p],dp[i][j+1][cnt][p]);
    			}
    		}
    	}
    	cout<<max(0,dp[n+1][0][0][0]); 
    	
    }
    
    

    G. Reducing Delivery Cost

    题意

    给定一张 n 个点 m 条边的带权无向图,记 d(u,v) 为 u 到 v 的最短路,给定 k 个点对 (ai,bi)。你可以使任意一条边的边权变为 0,求(∑d(ai,bi))的最小值

    思路

    思路:开始看到了路线免费,以为是出了分层最短路板子,看了看发现只让一条路免费。

    开始直接考虑暴力,枚举每条边,然后每个点进行dijkstra,最后取最小。复杂度O(n^2klogm);

    考虑一下对每个点其实可以先预处理,提前处理好每个点的对应的最短路。O(n^2logm)

    考虑免费的边的贡献。

    对每一个ki来说,边(a,b)有三种情况。

    1.开始不在其最短路路径上,免费后也不在其最短路路径上。

    2.开始不在其最短路路径上,免费后在其最短路路径上。

    3.开始在其最短路路径上,免费后在其最短路路径上。

    对于第一种情况,ki的最短路长度不变,仍然是原来的dis[ki.first][ki.second] (ki.first和ki.second分别代表其起点和终点)

    对于第二三种情况,ki的最短路长度可能变化,dis[ki.first][a]+dis[ki.second][b];dis[ki.first][b]+dis[ki.second][a];

    在这里插入图片描述

    那么枚举边,再枚举每个k,求出总和的最小.

    总时间复杂度O(mk+n^2logm)

    代码

    #include<bits/stdc++.h>
    #define re register
    #define inf 1e18
    #define int long long
    using namespace std;
    struct edge
    {
        int to,cost;
    };
    vector<edge>g[5005];//定义路径结构体
    vector<edge>p[5005];
    int n,m,k;
    int dis[5005];
    int d[1200][1200];
    struct node//定义堆结构体
    {
    	//(如果看不懂)https://www.cnblogs.com/ZERO-/p/9347296.html
    	int u,d;
    	bool operator<(const node&rhs)const
    	{
    		return d>rhs.d;
    	}
    };
    inline void djs(int s)
    {
    	for(re int i=1;i<=n;i++)dis[i]=inf;
    	dis[s]=0;
    	priority_queue<node>Q;//初始化
    	
    	node a ={s,0};
    	Q.push(a);//第一个node
    	
    	while(!Q.empty())
    	{
    		node fr=Q.top();Q.pop();
    		int u=fr.u,d=fr.d;
    		//取出并记录
    		if(d!=dis[u])continue;//避免处理无用数据,也就是dis[u]已经更新,之前未更新数据直接出栈,比如有一组数据 2 5,但是后面又入栈一组数据2 3,则2 5是无用数据
    		for(re int j=0;j<g[u].size();j++)
    		{
    			int tm=g[u][j].to;
    			if(dis[u]+g[u][j].cost<dis[tm])
    			{			 
                	dis[tm]=dis[u]+g[u][j].cost;
    				Q.push((node){tm,dis[tm]});
    			}
    		}
    	}
    	for(int i=1;i<=n;i++)
    	{
    		d[i][s]=dis[i];
    		d[s][i]=dis[i];
    	//	printf("##%d %d %d
    ",i,s,d[i][s]);
    	}
    }
    inline int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    main(void)
    {
    	cin>>n>>m>>k;
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++)
    		d[i][j]=inf;
    	for(int i=1;i<=n;i++)
    		d[i][i]=0;
    	int x,y,z;
    	vector<pair<int,int>>e1,e2;
    	for (re int i=1;i<=m;i++)
    	{
            edge tmp;
          	cin>>x>>y>>z;
          	tmp.cost=z;
          	tmp.to=y;
            g[x].push_back(tmp);   
            tmp.to=x;
            g[y].push_back(tmp);
            e1.push_back({x,y});
        }
        for(int i=1;i<=k;i++)
        {
        	int x=read();
        	int y=read();
        	edge tmp;
        	tmp.to=y;
    		p[x].push_back(tmp);
    		e2.push_back({x,y});
    	}
    	for(int i=1;i<=n;i++)
    	{
    		djs(i);
    	}
    	int ans=inf;
    	for(auto e:e1)
    	{
    		int x=e.first,y=e.second;
    		int index=0;
    		for(auto pa:e2)
    		{
    			int m=pa.first,n=pa.second;
    			index+=min(d[m][n],min(d[m][x]+d[y][n],d[m][y]+d[x][n]));;
    		}
    		ans=min(ans,index);
    	}
    	cout<<ans;
    }
    
    
  • 相关阅读:
    Web Designer Intern
    Internship UI/UX Web Designer
    HTML / CSS Frontend Software Engineer Internship
    CSS 07 文本
    CSS 06 背景
    CSS 05 尺寸大小
    CSS 04 注释
    CSS 03 选择器
    Why Ancient Greeks are Always Nude
    C#表示空字符
  • 原文地址:https://www.cnblogs.com/wangqianyv/p/13865935.html
Copyright © 2011-2022 走看看