zoukankan      html  css  js  c++  java
  • 2020hdu多校第一场比赛及补题

    第一场是朝鲜出题

    1004 Distinct Sub-palindromes

    跟榜开的这题,一开始猜是26的n次方,直接交一发wa了, 后来和队友想了半天,想到了abcabcabc,答案就是n<=3时是26的n次方, else ans = 26*25*24

    1005 Fibonacci Sum

    每个斐波纳契数的通项二项展开,再合并,是二项展开的套路。组合数要先预处理阶乘和阶乘逆元。

    比赛时队友过的这题。

    但是赛后我怎么写都T,把队友当时的AC代码交上去也T了,自闭了

    1009 Leading Robots

    队友写1005的时候我在想这题,想了挺久

    n个机器人赛跑,每个机器人初速度为0,加速度为ai,初始位置在pi,问有多少个机器人当过第一 (第一指独一无二的最前面的那个)

    容易想到下面两点

    一:n*(n-1)/2的比较次数肯定是不行的,要想办法减少比较次数

    二:加速度越大的最终排名一定越靠前,加速度大的人不会被加速度小的人从后方超越

    考虑3个人的情况,且这3个人编号越大,起点越靠后,加速度越大,

    设2号追上1号的时间 t1 ,3号追上2号的时间 t2 ,和3号追上1号的时间 t3,

    若t3 < t1,即3号比2号先超过1号,ans = 2; 若t2 > t1,即2号先超过1号,然后3号超过2号,ans = 3

    这里t1,t2,t3都用到了,  实际上只要用 t1和t2 或 t1和t3 就行了,

    t1和t3是两个人追上同一个人分别所用的时间,感觉很难有进一步的思路,下面思考t1和t2

    若t1<t2,即2号追上1号之前 3号追上了2号,3号先追上了1号,当了第一名,之后2号也无法当第一名了, 因为3号加速度比2号大,2号的存在简直像是可以被消除掉了(

    若t1>t2,2号还是能当第一名的,但如果后面又来了个4号,在2号当第一之前超过了2号,2号的存在又可以被消除了,而且4号把2号消除之前,已经把3号消除了

    于是可以想到一个单调栈做法,栈内保存的是每个人当第一的时刻,且单调递增, 每次加入一个加速度比栈内所有人都要大的新人,计算新人超越栈顶的时间,如果新人超越栈顶的时刻比栈顶人当第一的时刻小,就把栈顶人pop,栈顶人的存在就被消除了,如果新人超越栈顶的时刻比栈顶人当第一的时刻大,那么目前栈顶人还是能当第一,新人当第一的时刻就是新人超越栈顶的时刻,计录新人的这个时刻并把新人push入栈。如果新人在一开始的时候就是第一,那么他当第一的时刻就是0,栈内元素个数就是当过答案。

    至于多人同时保持当第一的情况,就特别处理。

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    const int MAXN = 5e4+7;
    const long long INF = 1e18+9;
    double eps = 1e-12;
    struct RBT{//机器人 
    	long long p,a;
    	double t = 0.0 ;
    }rbt[MAXN],st[MAXN];
    bool cmp(RBT x,RBT y){
    	if(x.a!=y.a) return y.a>x.a;
    	else return y.p>x.p;
    }
    int main()
    {	
    	int t,n,h;
    	cin>>t;
    	while(t--){
    		cin>>n;
    		int l = 0,r =0;
    		for(int i = 1;i<=n;i++){
    			scanf("%d%d",&rbt[i].p,&rbt[i].a);
    			rbt[i].t = 0.0; //初始化,比赛的时候就是少了这个,wa了几发 
    		}
    		sort(rbt+1,rbt+n+1,cmp);
    		for(int i = 1;i<=n;i++){
    			if(r&&rbt[i].p==st[r].p&&rbt[i].a==st[r].a){//特别处理 
    				rbt[i].t = st[r].t;
    			}
    			else while(r>l){
    				if(rbt[i].p>=st[r].p){ 
    					r--;
    					continue;
    				}	
    				long long da = rbt[i].a-st[r].a;
    				long long dx = st[r].p-rbt[i].p;
    				long long dvxdv = 2 * da * dx;
    				double dv = sqrt((double)dvxdv);
    				rbt[i].t = dv/da;
    				if(rbt[i].t<=st[r].t+eps) {
    					r--;
    				}
    				else break;
    			}
    			r++;
    			st[r] = rbt[i];
    		}
    		int ans = r;
    		for(int i = 2;i <= r;i++){//把相同第一的同位同速人删掉 
    			if(st[i-1].a==st[i].a&&st[i-1].p==st[i].p){
    				while(st[i].a==st[i-1].a&&st[i].p==st[i-1].p){
    					ans--;
    					i++;
    				}
    				ans--;
    			}
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    } 
    

      

     1006 Finding a MEX

    比赛时没做出来

    把度数大于350的节点称为大节点,其他节点称为小节点,每个大节点建一个对应线段树。

    求小节点的MEX就暴力求

    求大节点的MEX就要用到线段树,线段树维护的是最小值,查询MEX的时候,如果左半线段的最小值为0,就往左边查询,否则往右半段查询。

    每次修改值时,把该节点连接的所有大节点的线段树进行修改,要预处理每个节点连接哪些大节点

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    #include<time.h>
    using namespace std;
    struct NODE{
    	int l, r, mi;
    }tree[360][24000];
    int val[360][6000];//第i个线段树上某个值出现了几次 
    int a[100007];//节点上的值 
    int d[100007];//节点的度数 
    int ant[100007];//节点对应第几个线段树 
    vector<int>graph[100007];//存图 
    vector<int> gg[100007];//gg[i] 
    bool vis[360];//小节点上的vis 
    int tot;
    void build(int cnt,int pos,int l,int r){
    	tree[cnt][pos].l = l;
    	tree[cnt][pos].r = r;
    	if(l==r){
    		tree[cnt][pos].mi = min(val[cnt][tot],1);
    		tot++;
    		return;
    	}
    	int mid = l+r>>1;
    	build(cnt,pos<<1,l,mid);
    	build(cnt,pos<<1|1,mid+1,r);
    	tree[cnt][pos].mi = min(tree[cnt][pos<<1].mi,tree[cnt][pos<<1|1].mi);
    }
    void modify(int cnt,int pos,int p,int v){
    	if(tree[cnt][pos].l==tree[cnt][pos].r){
    		tree[cnt][pos].mi = v;
    		return;
    	}
    	int mid = tree[cnt][pos].l+tree[cnt][pos].r>>1;
    	if(p<=mid) modify(cnt,pos<<1,p,v);
    	else modify(cnt,pos<<1|1,p,v);
    	tree[cnt][pos].mi = min(tree[cnt][pos<<1].mi,tree[cnt][pos<<1|1].mi);
    }
    int query(int cnt,int pos,int l,int r){
    	if(tree[cnt][pos].l==tree[cnt][pos].r){
    		return tree[cnt][pos].l;
    	}
    	int mid = tree[cnt][pos].l+tree[cnt][pos].r>>1;
    	if(tree[cnt][pos<<1].mi==0) return query(cnt,pos<<1,l,mid);
    	else return query(cnt,pos<<1|1,mid+1,r);
    }
    int main()
    {
    	int t, n, m, q, u, v;
    	cin>>t;
    	while(t--){
    		cin>>n>>m;
    		for(int i = 1;i<=n;i++){
    			scanf("%d",&a[i]);
    			d[i] = 0;
    			graph[i].clear();
    			gg[i].clear();
    			ant[i] = 0;
    		}
    		for(int i = 1;i<360;i++){
    			for(int j = 0;j<6000;j++){
    				val[i][j] = 0;
    			}
    		}
    		for(int i = 1;i <= m;i++){
    			scanf("%d%d",&u,&v);
    			graph[u].push_back(v);
    			graph[v].push_back(u);
    			d[u]++;
    			d[v]++;
    		}
    		for(int i = 1;i<=n;i++){//存每个点连接的大节点 
    			for(int j = 0;j<graph[i].size();j++){
    				int po = graph[i][j];
    				if(d[po]>350) gg[i].push_back(po);
    			}
    		}
    		int cnt = 0;
    		for(int i = 1;i <= n;i++){//找出度数>350的节点建树 
    			if(d[i]>350){
    				cnt++;
    				ant[i] = cnt;
    				tot = 0;
    				for(int j = 0;j < d[i];j++){
    					int po = graph[i][j];
    					if(a[po]>d[i]){
    						val[cnt][d[i]]++;
    					}
    					else val[cnt][a[po]]++;
    				}
    				build(cnt,1,0,d[i]);
    			}
    		}
    		cin>>q;
    		int op,x;
    		for(int i = 1;i <= q;i++){
    			scanf("%d",&op);
    			if(op==1){
    				scanf("%d%d",&u,&x);
    				//printf("        %d\n",gg[u].size());
    				for(int j = 0;j<gg[u].size();j++){ 
    					int po = gg[u][j];				
    					int lo = a[u];
    					if(lo>d[po]) lo = d[po];
    					val[ant[po]][lo]--;
    					if(!val[ant[po]][lo]){
    						modify(ant[po],1,lo,0);
    					}
    					lo = x;
    					if(lo>d[po]) lo = d[po];
    					if(!val[ant[po]][lo]){
    						modify(ant[po],1,lo,1);
    					}
    					val[ant[po]][lo]++;					
    				}
    				a[u] = x;
    			}
    			else{
    				scanf("%d",&u);
    				if(d[u]>350){
    					printf("%d\n",query(ant[u],1,0,d[u]));
    				}
    				else{
    					for(int j = 0;j<=d[u];j++) vis[j] = false;
    					for(int j = 0;j<graph[u].size();j++){
    						int po = graph[u][j];
    						int lo = a[po];
    						if(lo>d[u]) lo = d[u];
    						vis[lo] = true;
    					} 
    					for(int j = 0;j<=d[u];j++){
    						if(!vis[j]){
    							printf("%d\n",j);
    							break;
    						}
    					}
    				}
    			}
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    嗯哼?考的好?不存在的。
    MyBatis的框架设计
    Mybatis数据源与连接池
    MyBatis事务管理机制
    MyBatis的SqlSession的工作过程
    Mybatis初始化机制
    [JVM-6]类加载器
    [JVM-5]类加载机制
    面试题
    TCC分布式事务的实现原理
  • 原文地址:https://www.cnblogs.com/ruanbaitql/p/13429461.html
Copyright © 2011-2022 走看看