CCPC XiangTan Invitational Programming Contest 2018

博主分享了参与ACM竞赛的经历,详细解析了从A题到I题的解题思路,涵盖了模拟、DP、图论、字符串转换、线性递推等算法,强调了思考过程的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A题 签到 但我很奇怪为什么别人跳过A先过了B

B题 将总时间分配给不同论文得到A*Xi的引用数 模拟了一下样例感觉把时间按照1,1,1,......的分法是最优的, 虽然不知道为什么

C题 在A题的基础上加了区间询问 一眼过去非常得分块 但是分不出来....最后是一个主席树的模板题(当然也确实看到了一些oier很莽的分块做法)

D题 长得像数学我就没管它了 其实是个DP技巧题 f[i][j]表示i个球分成j段的乘积和 需要用一个类似前缀和的优化 奇怪的是这个优化没卡住 反而是计算贡献的时候迟迟无法理解式子的正确性。。。总之很神奇。。。

E题 也特别地漂亮。长得很吓人的一道题,还是强制在线。不过考虑到每条边只会被更新一次,所以复杂度是可以保证的。每次在往上连lca的时候只会影响到这条链上处在并查集顶端的点,不知道应该怎么说qaq,开心地上CODE

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 10010
using namespace std;
int edgenum,vet[N],head[N],tim,jie[N],du[N],dep[N];
int fa[N][20],f[N];
int n,m,a,b,x0,y0,z0;
void add(int u,int v){
	edgenum++;vet[edgenum]=v;jie[edgenum]=head[u];head[u]=edgenum;
}
int lca(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	for(int i=15;i>=0;i--)if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
	for(int i=15;i>=0;i--)if(fa[u][i]!=fa[v][i]){
		u=fa[u][i];
		v=fa[v][i];
	}
	if(u!=v)return fa[u][0];else return u;
}
void dfs(int u,int ff,int d){
	int e=head[u];
	fa[u][0]=ff;
	dep[u]=d;
	for(int i=1;i<=15;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
	while(e>0){
		int v=vet[e];
		if(v!=ff){
			dfs(v,u,d+1);
		} 
		e=jie[e];
	}
}
int find(int x){
	if(x==f[x])return x;
	f[x]=find(f[x]);
	return f[x];
}
void update(int lcax,int u){
	if(u==1 || lcax==u)return;
	u=find(u);
	while(dep[lcax]+1<=dep[fa[u][0]]){
		int v=fa[u][0];
		z0^=du[v];
		du[v]--;
		z0^=du[v];
		v=find(v);
		f[u]=v;
		u=v;
	}
}
int main(){
	while(scanf("%d%d%d%d%d%d",&n,&m,&a,&b,&x0,&y0)!=EOF){
		edgenum=0;memset(head,0,sizeof(head));
		tim=0;
		memset(du,0,sizeof(du)); 
		memset(fa,0,sizeof(fa));
		z0=0;
		for(int i=1;i<n;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			u++;v++;
			add(u,v);add(v,u);
			du[u]++;du[v]++;
		}
		for(int i=1;i<=n;i++)z0=z0^du[i],f[i]=i;
		int x,y;
		dfs(1,0,1);
		for(int i=1;i<=m;i++){
			x=(a*x0+b*y0+z0)%n;
			y=(b*x0+a*y0+z0)%n;
			if(i==m)break;
			x++;y++;
			int u=lca(x,y); 
			update(u,x);
			x0=x-1,y0=y-1;
		} 
		printf("%d %d\n",x,y);
	} 
} 

F题 长得可签到了...确认了一下就写了...就wa了...从来没有深究过有关精度的问题...叉姐的题解:“long double是会挂的”...在没办法的情况下...只有多试错???

G题 string transformation 痛苦地卡了很久 主要还是大脑停止了思考...然后一直试图构造自己的样例方案...一直没发现其实它根本是个no solution...知道ab<->ba之后就可以做了...c字符作为分割标记...每段区间内分别统计a、b的个数是否合法就好

H题 不会做 题解是线性递推+高斯+矩阵快速幂 ....下面是sub老师的CODE

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <set>
#include <map>
#include <iostream>
#include <queue>
#include <cmath>
#define rep(i,n) for(int i=1;i<=n;++i)
using namespace std;
const int N=55,MOD=1e9+7;
int a[N],c[N],n,m;
struct mat{
	int a[N][N];
	mat operator*(mat p){
		mat ret;memset(ret.a,0,sizeof ret.a);
		rep(i,n+1)rep(k,n+1)if(a[i][k])rep(j,n+1)
			ret.a[i][j]=(ret.a[i][j]+1ll*a[i][k]*p.a[k][j])%MOD;
		return ret;
	}
}A,S;
int main(){
	while(~scanf("%d%d",&n,&m)){
		rep(i,n)scanf("%d",a+i);	
		rep(i,n)scanf("%d",c+i);
		rep(i,n){
			A.a[1][i]=(c[i]+a[i])%MOD;
			rep(j,i-1)A.a[1][i]=(A.a[1][i]+1ll*(MOD-a[i-j])*c[j])%MOD;
		}
		A.a[1][n+1]=0;
		rep(i,n)rep(j,n+1)A.a[i+1][j]=(i==j);
		rep(i,n+1)rep(j,n+1)S.a[i][j]=(i==j);
		for(;m;m>>=1,A=A*A)
			if(m&1)S=S*A;
		int ans=S.a[1][1];
		rep(i,n)ans=(ans+1ll*(MOD-S.a[i+1][1])*c[i]%MOD)%MOD;
		printf("%d\n",ans);
	}
}

I题 考虑到每次最多只有一个零能对LIS产生贡献 于是每次答案要不是L 要不是L+1 预处理出分别以i作为开头或结尾的lis dp值 然后对每一个fi 找出它下一个零后面那段区间中 gj+fi=L 同时aj尽可能大 那就把gj作为下标 一个遍历就好了 要特别注意零贡献在两端 以及n=1的情况 也是特别漂亮的一道题

J题 题意大致是给出一个染色图 一条边中至少需要染一个点 然后染色点点权值要尽可能小...一开始还以为是个匹配的图论...也是停止了思考...草稿乱打了一阵之后去正确模拟了一下样例...突然就明白了...

K题 也没什么好说的...那就不说了...


... ... ......吓得我赶紧把所有有趣的comment点了一遍...我感觉从此都有阴影了...(update:默默删去了cf那天的吐槽 看出这个阴影面积真的很大。。。感人了。。。)


anyway。。。。。还是很pleasing的。。。。


今天虽然早起了但是没能把H做掉...另外做得是之前差的青蛙题和细菌题,,,,hw2的blog就不更了...日子都过去好久了quq

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值