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;
}

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值