2019桂林电子科技大学校赛

星期天实在是太自闭了,各种状况各种错误,感觉自己的代码能力还是比较欠缺,而且队友的经验也相对比较不足,基本上一人卡题全队卡题。说到底还是自己的实力不够强,不能稳定把题给过掉。
最近要补的题实在是太多了,感觉还有很多很多要学的东西。实话说为什么这一届的水平比下一届差这么多,还是没有很努力去做事情。鸡汤多喝也无益,多多提升自己的水平才是最重要的。

A-串串

求问字符串里面有多少个本质不同的子串,是后缀自动机的一道模板题。

#include<bits/stdc++.h>
#define first F
#define second S
#define make_pair MP
typedef long long ll;
using namespace std;
const int N=1e5+50;
char s[N];
int len;
struct SAM{
	int last,cnt,nxt[N*2][26],fa[N*2],l[N*2];
	ll ans;
	void init(){
		last = cnt=1;
		memset(nxt[1],0,sizeof nxt[1]);
		fa[1]=0;ans=0;l[1]=0;
	}
	int inline newnode(){
		++cnt;
		memset(nxt[cnt],0,sizeof nxt[cnt]);
		fa[cnt]=l[cnt]=0;
		return cnt;
	}
	void add(int c){
		int p = last;
		int np = newnode();
		last = np;
		l[np] = l[p]+1;
		while (p&&!nxt[p][c]){
			nxt[p][c]=np;
			p = fa[p];
		}
		if (!p){
			fa[np]=1;
		}else{
			int q = nxt[p][c];
			if (l[q]==l[p]+1){
				fa[np] = q;
			}else{
				int nq = newnode();
				memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
				fa[nq] = fa[q];
				l[nq] = l[p]+1;
				fa[np]=fa[q]=nq;
				while (nxt[p][c]==q){
					nxt[p][c]=nq;
					p=fa[p];
				}
			}
		}
		ans+=l[last]-l[fa[last]];
	}
	void query(){
		init();
		for(int i=1;i<=len;i++){
			add(s[i]-'a');
		}
		printf("%lld\n",ans);
	}
}sam;
int main() {
    scanf("%s",s+1);
    len=strlen(s+1);
    sam.query();
    return 0;
}

C-二元

求问一个二元对里面选择k对,使得第一维的最小值和第二维的最小值之和最大。首先先考虑对第一维从大到小排序,然后枚举第一维,同时用一个优先队列维护第二维的最小值,更新答案。

#include<bits/stdc++.h>
#define first F
#define second S
#define make_pair MP
typedef long long ll;
using namespace std;
const int N=1e5+50;
struct node{
    int x,y;
}a[N];
bool cmp(node a,node b) {
    return a.x>b.x;
}
priority_queue< int,vector<int>,greater<int> > q;
int main() {
    int n,k,sum=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&a[i].x,&a[i].y);
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++) {
        if(i>=k+1) q.pop();
        q.push(a[i].y);
        if(i>=k) {
            sum=max(sum,a[i].x+q.top());
        }
    }
    printf("%d\n",sum);
    return 0;
}

C-寻找

对于一棵树,每次给出三个点,求问ab路径上的哪一个点到c的距离是最小的。可以发现这个点一定是lca(a,c),lca(b,c),lca(a,b)当中的一个。这里还要判断一下lca(a,c),lca(b,c)是不是还在这个路径上面,然后直接去计算那个最小的就可以了。

#include<bits/stdc++.h>
#define first F
#define second S
#define make_pair MP
typedef long long ll;
using namespace std;
const int N=1e5+50;
int dep[N],Fa[N][22];
vector<int>G[N];
void dfs(int u,int fa) {
    dep[u]=dep[fa]+1;
    Fa[u][0]=fa;
    for(int i=1;(1<<i)<=dep[u];i++) Fa[u][i]=Fa[Fa[u][i-1]][i-1];
    for(auto &v:G[u])  {
        if(v==fa) continue;
        dfs(v,u);
    }
}
int lca(int x,int y) {
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--) if((1<<i)<=dep[x]-dep[y]) x=Fa[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--) if(Fa[x][i]!=Fa[y][i]) x=Fa[x][i],y=Fa[y][i];
    return Fa[x][0];
}
int dis(int x,int y) { return dep[x]+dep[y]-2*dep[lca(x,y)]; }
int main() {
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0);
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++) {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        int x=lca(a,c),y=lca(b,c),z=lca(a,b);
        int vertex=z,ans=dis(z,c);
        if(dis(x,a)+dis(x,b)==dis(a,b)) {
            if(dis(x,c)<ans) {
                vertex=x,ans=dis(x,c);
            }
        }
        if(dis(y,a)+dis(y,b)==dis(a,b)) {
            if(dis(y,c)<ans) {
                vertex=y,ans=dis(y,c);
            }
        }
        printf("%d\n",vertex);
    }
    return 0;
}

F-点对

给出的定义其实就是强连通分量,做一次tarjan缩点,然后对每个环统计一下有多少个点对。

#include<bits/stdc++.h>
#define first F
#define second S
#define make_pair MP
typedef long long ll;
using namespace std;
const int N=305;
vector<int>G[N];
int tim=0,dfn[N],low[N];
stack<int>s;
bool ins[N];
int ans=0;
void tarjan(int u) {
    dfn[u]=low[u]=++tim;
    s.push(u),ins[u]=true;
    for(auto &v:G[u]) {
        if(!dfn[v]) {
            tarjan(v);
            low[u]=min(low[v],low[v]);
        }
        else if(ins[v]) {
            low[u]=min(low[u],low[v]);
        }
    }
    if(dfn[u]==low[u]) {
        int sum=1;
        while(!s.empty()) {
            int top=s.top();
            if(s.top()!=u) { s.pop(),++sum,ins[top]=false; }
            else break;
        }
        ans+=sum*(sum-1)/2;
    }
}
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    printf("%d\n",ans);
    return 0;
}

G-路径

给出一棵带权值树,然后要求最长的那个偶数边的链。偶数边的链可以认为是奇数点的链(不包含只有一个节点),dp[u][1]表示u节点出发向下的奇数个节点的链的最大值,dp[u][0]表示u节点出发向下偶数个节点的最大值。答案是对于每个节点出发的链和它的儿子出发的链连接起来。

#include<bits/stdc++.h>
#define first F
#define second S
#define make_pair MP
typedef long long ll;
using namespace std;
const int N=1e5+50;
struct edge{ int v,w; };
vector<edge> G[N];
ll dp[N][2];
ll ans=0; // 0代表偶数个结点 1代表奇数个结点
void dfs(int u,int fa) {
    dp[u][0]=-1e18;
    for(auto &e:G[u]) {
        int v=e.v,w=e.w;
        if(v==fa) continue;
        dfs(v,u);
        ans=max(ans,dp[u][0]+dp[v][1]+e.w);
        ans=max(ans,dp[u][1]+dp[v][0]+e.w);
        dp[u][0]=max(dp[u][0],dp[v][1]+e.w);
        dp[u][1]=max(dp[u][1],dp[v][0]+e.w);
    }
}
int main() {
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++) {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        G[u].push_back({v,w});
        G[v].push_back({u,w});
    }
    dfs(1,0);
    printf("%lld\n",ans);
    return 0;
}

I-选择

直接用dp[i][0]表示没有选择这个位置,dp[i][1]表示选择了这个位置,然后转移这个dp就好了。

#include<bits/stdc++.h>
#define first F
#define second S
#define make_pair MP
typedef long long ll;
using namespace std;
const int N=105;
int a[N];
ll dp[N][2];
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        int n;
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        dp[1][0]=0,dp[1][1]=a[1];
        for(int i=2;i<=n;i++) {
            dp[i][0]=max(dp[i-1][1],dp[i-1][0]);
            dp[i][1]=max(dp[i][1],dp[i-1][0]+a[i]);
        }
        printf("%lld\n",max(dp[n][0],dp[n][1]));
    }
    return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Tensorflow、OpenAI搭建的强化学习框架,训练机器自动操盘 强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一。它主要用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。强化学习的特点在于没有监督数据,只有奖励信号。 强化学习的常见模型是标准的马尔可夫决策过程(Markov Decision Process, MDP)。按给定条件,强化学习可分为基于模式的强化学习(model-based RL)和无模式强化学习(model-free RL),以及主动强化学习(active RL)和被动强化学习(passive RL)。强化学习的变体包括逆向强化学习、阶层强化学习和部分可观测系统的强化学习。求解强化学习问题所使用的算法可分为策略搜索算法和值函数(value function)算法两类。 强化学习理论受到行为主义心理学启发,侧重在线学习并试图在探索-利用(exploration-exploitation)间保持平衡。不同于监督学习和非监督学习,强化学习不要求预先给定任何数据,而是通过接收环境对动作的奖励(反馈)获得学习信息并更新模型参数。强化学习问题在信息论、博弈论、自动控制等领域有得到讨论,被用于解释有限理性条件下的平衡态、设计推荐系统和机器人交互系统。一些复杂的强化学习算法在一定程度上具备解决复杂问题的通用智能,可以在围棋和电子游戏中达到人类水平。 强化学习在工程领域的应用也相当广泛。例如,Facebook提出了开源强化学习平台Horizon,该平台利用强化学习来优化大规模生产系统。在医疗保健领域,RL系统能够为患者提供治疗策略,该系统能够利用以往的经验找到最优的策略,而无需生物系统的数学模型等先验信息,这使得基于RL的系统具有更广泛的适用性。 总的来说,强化学习是一种通过智能体与环境交互,以最大化累积奖励为目标的学习过程。它在许多领域都展现出了强大的应用潜力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值