【WHUST 2016 Individual Contest #3 】解题报告

A - The Revenge of the Princess’ Knight(HDU 4898)

题意:给一个字符环(字符串的尾连着字符串的首),切成K个子串,使得字典序排列最大的串最小。

思路:%%%WJMZBMR,看到这个名字我就知道八成又一道我不会做的题。

正解是LCP+二分答案+奇葩贪心。

待补。


B - Civilization(CodeForces 455C)

题意:在N<=3*10^5个点初始M<N条边的图中两个操作:1、找给定点所在强连通分量上直径 2、通过建立一条边的方法,合并给定两个点所在的强连通分量。

思路:联通块的直径通过两次dfs计算。该题现场没做出来是因为没有证明出来一个问题:一个联通块里到所有点最长距离最短的点一定是直径的中点。可以通过反证法证明,如果存在不是直径中点的点到其它点距离更短,那么该直径不满足直径的定义。——于是,每次合并只需要把两个图的直径中点相连,再更新直径中点就好了。

代码:待补。


C - Serega and Fun(CodeForces 455D)

题意:N个数,每次操作为:1、L,R区间上整体轮换右移一位。2、询问L,R区间上等于K的数字有多少个。

思路:%%%陆队:分块链表+双端队列(蒟蒻没这个模板)

代码:待补。


D - Couple doubi(HDU 4861)

题意:有k个球,第i个球的价值为 ( 1^i+2^i+...+(p-1)^i ) MOD p。两人轮流每次拿一个球,问先手能不能赢。

思路:甜蜜虐狗向打表找规律题???上来我就列了个式子发现所有i为奇数的情况下,价值都是0,于是问题来了,偶数情况下还是不能算,是不是有规律呢?把100以内的表打出来一看笑了——标号为p-1的倍数的球才是非0的,值为p-1,于是结果出来了……


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>

using namespace std;

/*
int x[1010];
int val[1010];
void run(int temp)
{
	val[1]=0;
	for(int i=1;i<temp;i++)
	{
		x[i]=i;
		val[1]+=x[i];
		val[1]%=temp;
	}
	printf("1 %d\n",val[1]);
	for(int i=2;i<=100;i++)
	{
		val[i]=0;
		for(int j=1;j<temp;j++)
		{
			x[j]*=j;
			x[j]%=temp;
			val[i]+=x[j];
			val[i]%=temp;
		}
		printf("%d %d\n",i,val[i]);
	}
}
*/
int main()
{
	/*
	run(2);
	run(3);
	run(5);
	run(7);
	run(11);
	*/
	int k,p;
	while(scanf("%d%d",&k,&p)!=EOF)
	{
		if(p==2)
		{
			if(k%2==0)
				printf("NO\n");
			else
				printf("YES\n");
		}
		else
		{
			if((k/(p-1))%2==0)
				printf("NO\n");
			else
				printf("YES\n");
		}
	}
	return 0;
}

E - Paths on the tree(HDU 4912)

题意:一棵树,树上有M个给定的路径,问你这些路径不相交的情况下最多能选多少条。

思路:树形dp嘛,我上来就在想这个题,一直写到最后发现TLE了……首先要Tarjan处理出来所有路径的LCA,然后按照dp去写,dp[i][0]表示不选用i点,i为根的子树上最多选多少条,dp[i][1]表示选i点最多选多少条。那么dp[i][0]=∑dp[j][1](j为i的子节点) dp[i][1]=max(dp[i][0],dp[A][0]+(dp[a1][0]-dp[A][1])+(dp[a2][0]-dp[a1][1])+...+dp[B][0]+dp[b1][0]-dp[B][1]+...)其中Aa1a2...b1B为一条LCA是i点的给定路径。这个情况下其实是O(N^2)的复杂度,无法接受。怎么办呢?——把dp改成贪心,将路径按LCA的深度排序,你会发现优先选择前面的一定是最优解——同等深度的不会交叉,选择更高深度与更低深度时明显更低深度不会影响到选择其它边,所以选择更低的优。dp都不用写。由于你每次选择一个路径后就标记所有路径上的点,所以碰到被标记过的点就可以停,这样复杂度其实是O(N)的,可以接受。

//#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<deque>
using namespace std;
const int MAXN=100020,MAXM=100010;

int N,M,ufs[MAXN],dis[MAXN];
vector <int> p[MAXN];//存图
vector <pair<int,int> > quest[MAXN];//u节点有关的询问、询问编号
int LCA[MAXM];
struct tri
{
	int a,b,lca;
}q[MAXM];
int f[MAXN],depth[MAXN];
bool cmp(tri x,tri y){return depth[x.lca]>depth[y.lca];}
int ans[MAXM];
bool vis[MAXN];
int find(int x){return ufs[x]==x?x:ufs[x]=find(ufs[x]);}
void Tarjan(int u)
{
	vis[u]=true;
	ufs[u]=u;
	for(unsigned int i=0;i<quest[u].size();i++)
	{
		if(vis[quest[u][i].first])
			LCA[quest[u][i].second]=find(quest[u][i].first);
	}
	for(unsigned int i=0;i<p[u].size();i++)
	{
		if(!vis[p[u][i]])
		{
			Tarjan(p[u][i]);
			ufs[p[u][i]]=u;
		}
	}
}

void dfs(int x)
{
	for(unsigned int i=0;i<p[x].size();i++)
	{
		if(p[x][i]==f[x])continue;
		f[p[x][i]]=x;
		depth[p[x][i]]=depth[x]+1;
		dfs(p[x][i]);
	}
}
int main()
{
	while(scanf("%d%d",&N,&M)!=EOF)
	{
		memset(LCA,0,sizeof(LCA));
		for(int i=1;i<=N;i++)ufs[i]=i;
		int u,v;
		for(int i=1;i<=N;i++)p[i].clear();
		for(int i=1;i<N;i++)
		{
			scanf("%d%d",&u,&v);
			p[u].push_back(v);
			p[v].push_back(u);
		}
		for(int i=1;i<=N;i++)quest[i].clear();
		for(int i=1;i<=M;i++)
		{
			scanf("%d%d",&u,&v);
			quest[u].push_back(make_pair(v,i));
			quest[v].push_back(make_pair(u,i));
			q[i].a=u;
			q[i].b=v;
		}
		memset(vis,false,sizeof(vis));
		Tarjan(1);
		for(int i=1;i<=M;i++)
			q[i].lca=LCA[i];
		
		depth[1]=1;
		f[1]=0;
		dfs(1);
		sort(q+1,q+M+1,cmp);
		memset(vis,false,sizeof(vis));
		int lca;
		bool flag;
		int ans=0;
		for(int i=1;i<=M;i++)
		{
			lca=q[i].lca;
			flag=false;
			if(vis[lca])flag=true;
			if(!flag)
				for(u=q[i].a;u!=lca;u=f[u])
					if(vis[u])
					{
						flag=true;
						break;
					}
			if(!flag)
				for(v=q[i].b;v!=lca;v=f[v])
					if(vis[v])
					{
						flag=true;
						break;
					}
			if(!flag)
			{
				ans++;
				vis[lca]=true;
				for(u=q[i].a;u!=lca;u=f[u])
					vis[u]=true;
				for(v=q[i].b;v!=lca;v=f[v])
					vis[v]=true;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

G - Boredom(CodeForces 455A)

题意:10^5个数字,数值范围在10^5,每次取走一个数字x得x分,并且要把值为x-1和x+1的都删掉。问最大得分。

思路:选择了取x就可以把等于x的取完,而不能选择相邻的数字,可列dp方程:

ans[i]=max(ans[i-2]+(long long)i*num[i],ans[i-1]);
ans[i]代表取到数值i的时候最大得分。不是取i就是取i-1。是不相邻的取,满足题意。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>


using namespace std;

int num[100010];
int N;
long long ans[100010];
int main()
{
	scanf("%d",&N);
	int temp;
	memset(num,0,sizeof(num));
	for(int i=1;i<=N;i++)
	{
		scanf("%d",&temp);
		num[temp]++;
	}
	ans[0]=0;
	ans[1]=num[1];
	for(int i=2;i<=100000;i++)
	{
		ans[i]=max(ans[i-2]+(long long)i*num[i],ans[i-1]);
	}
	printf("%I64d\n",ans[100000]);
	
	return 0;
}


J - A Lot of Games(CodeForces 455B)

题意:N<=10^5个字符串(总长度不超过10^5),拼一个word,两人轮流添加一个小写英文字符到word的末尾,如果word不能是这些字符串中任意一个字符串的前缀了就算失败。总共玩K<=10^9局,第i局的失败方为第i+1局的先手,如果两人都使用最优策略,问先手赢还是后手赢。

思路:建立Trie树,在Trie树上dp找到是否有先手必胜和先手必输策略——你想最后一局赢,需要一个先手必胜策略,因为如果后手必胜而且先手无法必胜,那么每轮的先手方必输,输了还是先手,最后一定是先手输。如果有先手必胜策略了,你还要有先手必输策略,这样你前K-1局都使用先手必输策略,再最后一局使用先手必胜策略,否则先手是必胜的,无法输,那只要判断K%2是不是1,如果是1则先手赢,是0则后手赢。

至于dp思路,0代表输,1代表赢。如果是叶子节点(某个非其它单词前缀的单词的末尾)标记为先手必胜,1(只有一个字符当然是先手必胜);非叶子节点,决策先手必输时,有0则为1,无0则为0,先手必胜时,有1则为0,有0则为1。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>

#include<string>

using namespace std;

int N,K,tot;
string str;
int len;
struct Node
{
	//int f;
	//char ch;
	int son[26];
}tree[100010];
bool win[100010];
void insert(int node,int step)
{
	if(step>=len)
	{
		return;
	}
	int tmp=str[step]-'a';
	if(tree[node].son[tmp])
	{
		insert(tree[node].son[tmp],step+1);
	}
	else
	{
		tree[node].son[tmp]=++tot;
		//tree[tot].ch=str[step];
		//tree[tot].f=node;
		for(int i=0;i<26;i++)tree[tot].son[i]=0;
		insert(tree[node].son[tmp],step+1);
	}
}
void dfs_lose(int x)
{
	bool flag=true,zero=false;
	for(int i=0;i<26;i++)
		if(tree[x].son[i])
		{
			flag=false;
			dfs_lose(tree[x].son[i]);
			if(win[tree[x].son[i]]==0)
				zero=true;
		}
	if(flag)
	{
		win[x]=true;
	}
	else
	{
		if(zero)
			win[x]=true;
		else
			win[x]=false;
	}
}
void dfs_win(int x)
{
	bool flag=true,one=false;
	for(int i=0;i<26;i++)
		if(tree[x].son[i])
		{
			flag=false;
			dfs_win(tree[x].son[i]);
			if(win[tree[x].son[i]]==1)
				one=true;
		}
	if(flag)
	{
		win[x]=true;
	}
	else
	{
		if(one)
			win[x]=false;
		else
			win[x]=true;
	}
}
int main()
{
	cin.sync_with_stdio(false);
	cin>>N>>K;
	tot=0;
	//tree[0].f=0;
	for(int i=0;i<26;i++)tree[0].son[i]=0;
	for(int i=1;i<=N;i++)
	{
		cin>>str;
		len=str.length();
		insert(0,0);
	}
	bool winner[2];
	dfs_lose(0);
	winner[0]=true;
	for(int i=0;i<26;i++)
		if(tree[0].son[i])
			if(win[tree[0].son[i]]==0)
				winner[0]=false;
	dfs_win(0);
	winner[1]=false;
	for(int i=0;i<26;i++)
		if(tree[0].son[i])
			if(win[tree[0].son[i]])
				winner[1]=true;
	if(winner[0]==false && winner[1]==true)//有先手必输和先手必胜策略
	{
		printf("First\n");
	}
	else
	{
		if(winner[1]==true && K%2==1)//先手是必胜的  而且  总局数为奇数局
			printf("First\n");
		else
			printf("Second\n");
	}
	return 0;
}



























深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值