牛客训练赛40(A和C)

链接:https://ac.nowcoder.com/acm/contest/369/A
来源:牛客网
 

题目描述

若你摘得小的星星 你将得到小的幸福 

若你摘得大的星星 你将得到大的财富 

若两者都能摘得 你将得到永远的愿望 

摘星是罪孽的宽恕 摘星是夜晚的奇迹 

抓住它吧 你所期望的那颗星

无法触及,因而耀眼  

明明触及了,却还是耀眼

——《少女☆歌剧 Revue·Starlight》

题目描述

"我明白。"

作为这命运剧场永远的观众,小D一直注视着这片星光璀璨的舞台,舞台上,少女们的身姿演绎出了一幕幕动人的场景,令人回味无穷。

有的时候,小D也会自己写一些歌曲,来加入Starlight的剧本,使得剧本充满了新的生命力。

现在小D又要准备写乐谱了,小D写谱的方式比较独特。他会先写出一个按照音符出现顺序排成的序列,再进一步整合,每次整合会选取相邻的三个作为三和弦。整合次数无限。

小D选取的音符形如D5 F6这种形式,例如D5表示D大调sol(这里不考虑升降音)为了方便生成乐谱,他将这些音符进一步转化了,小D给C D E F G A B重新编号成了1 2 3 4 5 6 7,之后新的音符编号生成方式应为(字母对应的标号-1)*7+数字,例如C7=(1−1)×7+7=7C7=(1−1)×7+7=7

但小D讨厌一些他所认为的不优美的和弦,因此他并不希望自己的谱子里面有可能出现这样的三和弦,也就说音符组成的序列里不应该存在他所讨厌的子段,假如C5 F1 A2这三个音符凑成的和弦小D不喜欢,那么序列里面就不能出现C5 F1 A2,C5 A2 F1,A2 C5 F1,A2 F1 C5,F1 A2 C5,F1 C5 A2这六种子段。

现在小D正在推算有多少合法的序列,答案对 109+7109+7 取模。

星屑飘洒的舞台上,可人绽放的爱之花,请努力让大家星光闪耀吧!

输入描述:

第一行为两个整数 n, q ,表示序列的长度和有多少和弦小D不喜欢.
接下来 q 行,每行三个整数 a, b, c ,表示小D不想出现的和弦

输出描述:

一行一个整数,表示答案

示例1

输入

复制

10 10
18 3 3
43 28 22
42 28 3
48 48 4
29 9 31
47 9 22
1 22 49
15 48 29
2 8 27
4 24 34

输出

复制

382785822

示例2

输入

复制

3 1
1 2 3

输出

复制

117643

说明

 

一共有6种不合法的序列:

1 2 3

1 3 2

2 1 3

2 3 1

3 1 2

3 2 1

答案为493−6=117643493−6=117643

备注:

3≤n≤500,0≤q≤117649,1≤a,b,c≤49

我发现像这类求个数、种数都离不开DP,DFS也可以做,不过必然超时

非常妙的DP。就像cf div533那场C题也是求个数

div 533 的C题题意大概是给出n,l,r,分别是数组长度,可选择的数在l,r区间,求n个数组成一堆数,这堆数是3的倍数的个数,(数必须从给定区间选择,可以重复选择)

这题题意大概是给出n数组长度,和一堆3个连续的数(不合法的数),问组成合法的数的个数;

首先想到的是4维数组,当然是超内存::

#include <cstdio>
#include <iostream>
using namespace std;
const int mod = 1e9+7;
const int siz = 501;
const int N = 50;
int dp[siz][N][N][N];
int n,m;
int f[50][50][50];

int main(){
    	scanf("%d%d",&n,&m);
        while(m--){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            f[a][b][c] = f[a][c][b] = f[b][a][c] = f[b][c][a]
                =f[c][a][b] = f[c][b][a] = 1;
        }
        for(int i=1;i<=49;i++){
            for(int j=1;j<=49;j++){
                dp[2][0][i][j] = 1;
            }
        }
        
        int ans = 0;
        for(int i=3;i<=n;i++){
            for(int j=1;j<=49;j++){
                for(int k=1;k<=49;k++){
                    for(int p=1;p<=49;p++){
                        if(f[j][k][p] == 0)    dp[i][j][k][p] = dp[i-1][0][j][k]%mod;
                        else    dp[i][j][k][p] = 0;   
                        if(i==n)    ans = (ans + dp[i][j][k][p])%mod;
                        dp[i][0][k][p] = (dp[i][0][k][p] + dp[i][j][k][p])%mod;
                    }
                }
            }
        }
        printf("%d\n",ans);
    return 0;
}

优化了一下,加了一个滚动数组(注释部分):看了别人代码发现滚动数组可以不用,又优化了一下:

#include <cstdio>
#include <iostream>
using namespace std;
const int mod = 1e9+7;
const int siz = 505;
const int N = 50;
int dp[siz][N][N];
int num[siz][N][N];
int n,m;
int f[50][50][50];
int main(){
    scanf("%d%d",&n,&m);
        while(m--)
		{
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            f[a][b][c] = f[a][c][b] = f[b][a][c] = f[b][c][a]
                =f[c][a][b] = f[c][b][a] = 1;
        }
        for(int i=1;i<=49;i++)
            for(int j=1;j<=49;j++)
                dp[2][i][j] = num[2][i][j] = 1;    
        int ans = 0;
        
        for(int i=3;i<=n;i++){
            for(int j=1;j<=49;j++){
                for(int k=1;k<=49;k++){
                    for(int p=1;p<=49;p++){
                        if(f[j][k][p] == 0)    dp[i][k][p] = (dp[i][k][p] + dp[i-1][j][k])%mod;
						//num[i-1][j][k];//
//                        else   dp[i][k][p] = 0;  
                        //if(i==n)    ans = (ans + dp[i][k][p])%mod;
//                        
//                        num[i][k][p] = (num[i][k][p] + dp[i][k][p])%mod;
                    }
                }
            }
        }
        for(int i=1;i<=49;i++){
        	for(int j=1;j<=49;j++){
        		ans = (ans + dp[n][i][j]) % mod;
			}
		}
        printf("%d\n",ans);
    return 0;
}

,顺带写一下C题,这题是补的,当时不会写

链接:https://ac.nowcoder.com/acm/contest/369/C
来源:牛客网
 

题目描述

小A给你了一棵树,对于这棵树上的每一条边,你都可以将它复制任意(可以为0)次(即在这条边连接的两个点之间再加一条边权相同的边),求所有可能新形成的图中欧拉路的最短长度

欧拉路:从图中任意一个点开始到图中任意一个点结束的路径,并且图中每条边只通过恰好一次

输入描述:

第一行一个数 n ,表示节点个数

接下来 n-1 行,每行三个整数 u,v,w,表示有一条 u 到 v 边权为 w 的无向边

保证数据是一棵树

输出描述:

一行一个整数,表示答案

示例1

输入

复制

4
1 2 1
1 3 1
1 4 2

输出

复制

5

说明

一种可能的方案为复制 <1,2,1> 这条边一次,欧拉路为4->1->2->1->3

备注:

 

1≤n≤2×1051≤n≤2×105
1≤ui,vi≤n1≤ui,vi≤n
1≤wi≤1041≤wi≤104

官方题解:

像我图论这么弱的,不知道怎么求树的直径,又又又看了别人的代码(qwq,我好弱呀),dp求直径的方法也不会,以后再学吧。

下面是两次DFS求的直径,类似迪杰斯特拉求单点最短路,bfs求直径也是可以的~~

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll d[maxn],n;
bool vis[maxn];
struct node
{
	int v;
	ll w;
	node(int a,int b){
		v=a;
		w=b;
	}
}; 
vector<node >G[maxn];
void dfs(int u)
{
	vis[u]=1;
	int siz=G[u].size();
	for(int i=0;i<siz;i++)
	{
		int v=G[u][i].v;
		if(vis[v]) continue;
		d[v]=d[u]+G[u][i].w;
		dfs(v);
	}
}
int main()
{
	cin>>n;
	int u,v;
	ll w;
	ll res=0;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d%lld",&u,&v,&w);
		G[u].push_back(node(v,w));
		G[v].push_back(node(u,w));
		res+=w;
	}
	dfs(1);
	int start=1;
	ll mx=-1;
	for(int i=1;i<=n;i++)
	{
		if(d[i]>mx)
		{
			mx=d[i];
			start=i;
		}
	}
	memset(d,0,sizeof(d));
	memset(vis,0,sizeof(vis));
	dfs(start);
	mx=-1;
	for(int i=1;i<=n;i++)
	{
		if(d[i]>mx)
		{
			mx=d[i];
			start=i;
		}
	}
	cout<<res*2-mx<<endl;
}

这是用结构体保存点边信息,看了一堆代码,有种保存点边信息的方法好优秀的感觉:学到了~

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
vector<ll >G[maxn],E[maxn];
ll d[maxn],n;
bool vis[maxn];
void dfs(int u)
{
	vis[u]=1;
	//cout<<u<<endl; 
	int siz=G[u].size();
	for(int i=0;i<siz;i++)
	{
		int v=G[u][i];
		if(vis[v]) continue;
		d[v]=d[u]+E[u][i];
		dfs(v);
	}
}
int main()
{
	cin>>n;
	int u,v;
	ll w;
	ll res=0;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d%lld",&u,&v,&w);
		G[u].push_back(v);
		G[v].push_back(u);
		E[u].push_back(w);
		E[v].push_back(w);
		res+=w;
	}
	dfs(1);
	int start=1;
	ll mx=-1;
	for(int i=1;i<=n;i++)
	{
		if(d[i]>mx)
		{
			mx=d[i];
			start=i;
		}
	}
	memset(d,0,sizeof(d));
	memset(vis,0,sizeof(vis));
	dfs(start);
	mx=-1;
	for(int i=1;i<=n;i++)
	{
		if(d[i]>mx)
		{
			mx=d[i];
			start=i;
		}
	}
	cout<<res*2-mx<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/87704971