zoukankan      html  css  js  c++  java
  • 2021.11.6模拟总结

    前言

    流程复盘

    其实时间规划不够好,主要是第一题写的时间太长了。
    写代码+调用了 (50min) 左右,而且是写的 (40pts) 暴力,应该在半个点左右写完比较理想,可能一早上脑子还是不够清醒。
    写完 (T1) 基本就过了 (1h+30min) 了,然后去开了个 (T3) 的特判贪心,结果写完了证出来不对,有点小烦,回去写了 (T2) 的暴力记搜。
    这些题的暴力都不是特别好写,数据范围正好把最暴力的暴力卡掉。
    (T2) 感觉复杂度直逼 (10^8),但是想想暴力应该只能这么写了吧(?
    最后剩了 (1h) 打完 (T4) 错误做法并发现假了,赶紧回到 (T3) 写了个假的贪心希望能得分。
    期望得分:(40+30+10+0=80pts)
    实际得分:(40+10+30+0=80pts)
    说实话一开始心里没底,因为不知道大家做的怎么样,毕竟我都没上 (100pts)
    结果出来还行,(rk3)

    总结

    罗列了这么多,需要总结点问题出来。

    • 刚开始做题的时候进入状态较慢,虽然没有好的解决方法,但是还是尽量吧。
    • 接着上一条,打暴力不够稳,这次 (T1) 依赖样例调出了三处错误,尽量要再仔细点。
    • (T3) 又卡在贪心的思路上了,虽然有贪心思想,但实际上是 DP。
    • 不够紧张!!!(不过这有时候也不是没有好处)
    • 水平不够(这根本不用说啊喂!)

    题解

    T1 game

    考场二分写的 (O(n^2 log^2 n)),略微有点悬,实际上不用二分。
    直接过程中贪心更新答案即可。
    正解带权并查集,看着并不是很复杂,但是实际上感觉很有难度。
    首先是根据 (a_i) 的大小关系固定,所以排序。
    相当于在维护连通块的时候同时维护每个点的答案。

    代码

    game-AC
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    #define FCC fclose(stdin),fclose(stdout)
    const int INF = 0x3f3f3f3f,N = 1e6+10;
    inline ll read()
    {
    	ll ret=0ll;char ch=' ',c=getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    	return ch=='-'?-ret:ret;
    }
    int n,m,maxn;
    struct node 
    {
    	int hp,sw,id;
    	bool operator <(const node &oth) const 
    	{return hp<oth.hp;}
    }p[N];
    int head[N<<1],ecnt=-1;
    struct edge
    {
    	int nxt,to;
    }a[N<<1];
    void init_edge(){memset(head,-1,sizeof(head)),ecnt=-1;}
    inline void add_edge(int x,int y)
    {
    	a[++ecnt]=(edge){head[x],y};
    	head[x]=ecnt;
    }
    int f[N<<1],g[N<<1];
    int find(int x)
    {
    	if(f[x]==x) return x;
    	int fa=find(f[x]);
    	g[x]=max(g[x],g[f[x]]);
    	return f[x]=fa;
    }
    int main()
    {
    	init_edge();
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) p[i].hp=read(),p[i].id=i;
    	for(int i=1;i<=n;i++) p[i].sw=read(),p[i].sw=max(p[i].sw,p[i].hp);
    	//for(int i=1;i<=n;i++) printf("p[%d]=%d ",p[i].id,p[i].sw);
    	for(int i=1;i<=m;i++)
    	{
    		int u=read(),v=read();
    		add_edge(u,v),add_edge(v,u);
    	}
    	sort(p+1,p+n+1); 
    	//for(int i=1;i<=n;i++) printf("p[%d]=%d ",p[i].id,p[i].sw);
    	for(int i=1;i<=n;i++) 
    	{
    		f[i+n]=i+n;//建立一个新的虚点,连接两个连通块,防止信息错乱 
    		int u=p[i].id;
    		for(int j=head[u];~j;j=a[j].nxt)
    		{
    			int v=a[j].to;
    			if(!f[v]) continue;
    		//	printf("u=%d,v=%d
    ",u,v);
    			v=find(v);
    			if(p[v].sw<p[i].hp) g[v]=p[i].hp;
    			p[i+n].sw=max(p[i+n].sw,p[v].sw);
    			f[v]=i+n;
    		}
    		f[u]=i+n;
    		g[u]=p[i].hp;		
    		p[i+n].sw=max(p[i+n].sw,p[i].sw);
    		//printf("sw[%d]=%d
    ",u,p[u].sw);
    		//printf("merge %d to %d, sward=%d
    ",u,i+n,p[i+n].sw); 
    	}
    	for(int i=1;i<=n;i++)
    	{
    		find(i);
    		printf("%d ",g[i]); 
    	}
    	return 0;
    }
    /*
    in1:
    4 4
    1 3 7 5
    2 4 6 8
    1 2
    2 3 
    3 4 
    4 1
    out1: 5 5 7 5 
    in2:
    4 3
    3 1 2 4
    4 2 3 5
    1 2
    2 3 
    3 4 
    out2: 3 1 2 4
    */
    

    T2 divide 分治

    暴力模拟加记搜只过了 (10pts),想过 (30pts) 需要预处理来 (O(1)) 回答询问,问了 fxj,也需要一点期望的知识,用 (dp(l,r,k)) 记录概率,答案是一个 (Sigma),具体就不展开了。
    满分大概是转换模型,对于每一个点单独考虑贡献,当且仅当它是某一段第一个被选,才产生贡献,$O(n) $预处理逆元的前缀和即可做到 (O(1)) 回答某个询问。
    实际上这个模型类似于给定一棵有根树,每次随机删去树上某个点以及其子树,求期望多少次能删完。

    T3 fief 封地

    看来以后假贪心能写还是要写上。
    当时证明出来比较 (naive) 的贪心假了之后有点摆烂了,直接换题(换题没问题,但没接着思考就不对了)。
    实际根据基本的贪心排序,可以接着设计出 DP,就算不优化也能的高分了。
    懒得讲怎么做了...

    T4 染色

    写完并查集,挑来挑去发现假了而且改不对。
    很难而且没时间,就放弃了,有关的性质也没怎么看出来。
    水平不够。

  • 相关阅读:
    雨中梦游
    最后一次为你哭
    poj3169 Layout
    poj2253 Frogger
    钟爱一生
    POJ2668解题报告
    魅力泸西
    android学习笔记09(activity的生命周期)
    poj 3468 A Simple Problem with Integers
    android学习笔记之多线程(二)
  • 原文地址:https://www.cnblogs.com/conprour/p/15518149.html
Copyright © 2011-2022 走看看