zoukankan      html  css  js  c++  java
  • 20210621模拟

    Day1

    T1

    可以线段树维护区间线性基的并,然后查询

    怎么查询呢?能贡献1就贡献1

    但是我OJ上T了,lemon又RE了,打算把LCA写完再去调调(正解调完再说)

    正解:

    我们知道线性基是一个极大线性无关组,同时一个线性空间中的任意线性无关组是等价的

    我们可以扫描线,枚举右端点,那么对于一个左端点,我们只需要知道这个区间内的一个线性无关组就可以了

    我们考虑什么时候线性无关组会发生变化,假设我们从右往左加数的话,线性无关组变化意味着极大线性无关组大小的变化,因为新加的数一定和当前的极大线性无关组线性无关,于是极大线性无关组的大小会增加 1

    同时我们知道线性基大小不会超过 30,于是我们可以对所有 i,在序列左边维护线性无关组大小为 i 时的一个线性基

    考虑增加一个数时会产生怎样的变化,容易发现存在某个数 k,使得当 i ≤ k 时线性基大小 +1,当 i > k 时线性基大小不变。这样我们也可以得到从右往左大小第一次达到每个线性基时的端点。

    考虑我们之前维护端点的过程,那么后 i 个端点实际上就是一个大小为 i 的线性无关组。

    容易发现,我们将位置在前面的数异或位置在后面的数,并不会对我们的答案产生影响。所以实际上我们仍然可以维护线性基,并且只需维护 1 个

    T2

    连边跑最短路,但是更新的时候要加上等车的时间

    T3

    给 r 对无向边,求出一个最大的边集,使得不包含在同一对中的无向边,且不包括环

    (r^3),但是T 1e4,行吧,这部分分设的真不错

    Day2

    T1

    n 为偶数时显然奇数位的数位和等于偶数位的数位和,所以答案就是 (10^{frac{n}{2}})

    n=4k+1 时,我们用(x_i)表示第 i 位的数字:

    (2(x_1 +x_3 +...+x_{frac{n}{2}-1})+x_{frac{n}{2}+1} =2(x_2 +x_4 +...+x_{frac{n}{2}}))

    那么我们可以枚举 (x_{frac{n}{2}+1}),问题变为求 (dfrac{n}{2}) 个不超过 9 的非负整数和为 m 的方案数,这不难 O(n)容斥求出。

    怎么容斥呢?我再想想,没好好上数学课就是不行啊……容斥都忘了,哎

    我们可以先求出所有情况不管合不合法,然后减掉一个>10,加两个>10……

    有i个大于10的情况数怎么求呢?首先我得选出哪i个盒子,C(n,i)

    然后对于一种i个盒子,可以先给i个盒子每个各10个球,剩下的可以m-10( imes)i隔板

    最后的答案就是(C(n,i) imes C(m-10 imes i+n-1,n-1))

    n=4k+3 时与上面类似。

    时间复杂度 O(tn)

    T2

    贪心的发现,如果奇偶分别的相对顺序不变,答案一定最小,这是充分条件,答案最小不一定相对顺序不变

    我们可以求出他相对顺序不变时的情况,然后再调换成字典序最小

    什么时候答案不变呢,假设两个元素的初始位置为(a,b),最后的第一次调换后的位置为(pa,pb),如果pa相对a和pb相对于b的方向相同,且调换后也满足这个性质就可以换

    简单来说其实就是因为绝对值符号

    之前是pa-a+pb-b,之后是pa-b+pb-a,不难发现二者是相等的,这样每次遇到一个可调换的位置,把待调换的最小值放上去就好了

    我是用优先队列维护的,代码出奇的长,看网上写的才40行,我写了120行左右,其实有很多重复的部分,我合并了其中的一小部分,而网上的代码用一些打标记的位运算合并了所有情况

    其实我写的时候还是蛮冷静了,思路也算清晰,看一下把看一下吧

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #define B cout<<"Breakpoint"<<endl;
    #define O(x) cout<<#x<<" "<<x<<endl;
    #define o(x) cout<<#x<<" "<<x<<" ";
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a;
    }
    const int maxn = 1e5+10;
    int n,a[maxn];
    struct node{
    	int pos,op;
    }spot[maxn];
    bool cmp1(node x,node y){return (x.pos == y.pos) ? x.op < y.op : x.pos < y.pos;}
    bool cmp2(node x,node y){return (x.pos == y.pos) ? x.op > y.op : x.pos < y.pos;}
    int ans1[maxn],ans2[maxn],pos1[maxn],pos2[maxn];
    void getans(int op,int l,int p[],int answer[]){
    	priority_queue<int,vector<int>,greater<int> > q1;
    	priority_queue<int> q2;
    	int cnt = 0;
    	for (int i = 1;i <= n;i++){
    		if (p[i] >= i&&a[i]%2 == op) spot[++cnt] = (node){i,0},spot[++cnt] = (node){p[i],1};
    	}
    	sort(spot+1,spot+cnt+1,cmp1);
    	for (int i = 1;i <= cnt;i++){
    		if (spot[i].op == 0) q1.push(a[spot[i].pos]);
    		else{
    			int x = q1.top();q1.pop();
    			answer[spot[i].pos] = x;
    		}
    	}
    	cnt = 0;
    	for (int i = 1;i <= n;i++){
    		if (p[i] < i&&a[i]%2 == op) spot[++cnt] = (node){i,0},spot[++cnt] = (node){p[i],1};
    	}
    	sort(spot+1,spot+cnt+1,cmp2);
    	for (int i = cnt;i >= 1;i--){
    		if (spot[i].op == 0) q2.push(a[spot[i].pos]);
    		else{
    			int x = q2.top();q2.pop();
    			answer[spot[i].pos] = x;
    		}
    	}
    }
    void subtask1(){
    	int cnt1 = 0,cnt2 = -1;
    	for (int i = 1;i <= n;i++){
    		if (a[i]&1) pos1[i] = (cnt1 += 2);
    		else pos2[i] = (cnt2 += 2);
    	}
    	getans(0,cnt2,pos2,ans2),getans(1,cnt1,pos1,ans1);
    	for (int i = 1;i <= n;i++){
    		if (i&1) printf("%d ",ans2[i]);
    		else printf("%d ",ans1[i]);
    	} 
    }
    int anss1[maxn],anss2[maxn];
    void subtask2(){
    	int cnt1 = 0,cnt2 = -1;
    	int num1 = 0,num2 = 0;
    	for (int i = 1;i <= n;i++){
    		if (a[i]&1) pos1[i] = (cnt1 += 2),num1 += abs(i-pos1[i]);
    		else pos2[i] = (cnt2 += 2),num1 += abs(i-pos2[i]);
    	}
    	getans(0,cnt2,pos2,ans2),getans(1,cnt1,pos1,ans1);
    	for (int i = 1;i <= n;i++){
    		if (i&1) anss1[i] = ans2[i];
    		else anss1[i] = ans1[i];
    	} 
    	cnt1 = -1,cnt2 = 0;
    	for (int i = 1;i <= n;i++) pos1[i] = pos2[i] = ans1[i] = ans2[i] = 0;
    	for (int i = 1;i <= n;i++){
    		if (a[i]&1) pos1[i] = (cnt1 += 2),num2 += abs(i-pos1[i]);
    		else pos2[i] = (cnt2 += 2),num2 += abs(i-pos2[i]);
    	}
    	getans(0,cnt2,pos2,ans2),getans(1,cnt1,pos1,ans1);
    	for (int i = 1;i <= n;i++){
    		if (i&1) anss2[i] = ans1[i];
    		else anss2[i] = ans2[i];
    	} 
    	if (num1 < num2) for (int i = 1;i <= n;i++) printf("%d ",anss1[i]);
    	if (num1 > num2) for (int i = 1;i <= n;i++) printf("%d ",anss2[i]);
    	if (num1 == num2){
    		if (anss1[1] < anss2[1]) for (int i = 1;i <= n;i++) printf("%d ",anss1[i]);
    		else for (int i = 1;i <= n;i++) printf("%d ",anss2[i]);
    	}
    }
    void subtask3(){
    	int cnt1 = -1,cnt2 = 0;
    	for (int i = 1;i <= n;i++){
    		if (a[i]&1) pos1[i] = (cnt1 += 2);
    		else pos2[i] = (cnt2 += 2);
    	}
    /*	for (int i = 1;i <= n;i++) cout<<pos1[i]<<" ";
    	cout<<endl;
    	for (int i = 1;i <= n;i++) cout<<pos2[i]<<" ";
    	cout<<endl;
    */
    	getans(0,cnt2,pos2,ans2),getans(1,cnt1,pos1,ans1);
    	for (int i = 1;i <= n;i++){
    		if (i&1) printf("%d ",ans1[i]);
    		else printf("%d ",ans2[i]);
    	} 
    }
    int main(){
    	freopen("sequence.in","r",stdin);
    	freopen("sequence.out","w",stdout);
    	n = read();int num = 0;
    	for (int i = 1;i <= n;i++) a[i] = read(),num += (a[i]&1);
    	if (num < n-num) subtask1();
    	if (num == n-num) subtask2();
    	if (num > n-num) subtask3();
    	return 0;
    }
    /*
    5
    5 3 1 4 2
    */
    

    Day3

    T1

    构造题,就是看一共能构造出多少个不同方向上的'L'形

    发现对于一个(2 imes 2)的一个方格对答案的贡献为4,如果方格缺一个角对答案的贡献为1

    这样我们每次尽可能多的往答案上凑

    (kgeq 2 imes(m-1)),说明我一整行都可以填满,那我就填一整行

    否则设一个量(tmp = frac{(k-1)}{4})为什么减一呢,因为我这一行一定填不满,一定会出现四个(2 imes 2)的方格缺一个角,最后会多出一个贡献

    这样我最开始连续填入(frac{(k-1)}{4}+1)个'',这是整方格的贡献,剩下的我交叉着填,除了最后一个格子,每填一个'',左右都会产生一个残缺的方格,他会产生2的贡献,最后一个格子会产生1的贡献

    如果还是没填完,剩余的k只有1,2,3,4四种取值,我们分情况讨论

    如果k = 1,行首填一个'*'就好了,当然有其他方案

    如果k = 2,上一行头会有两种情况''或者'.',第一种情况,当前行可以填'.',第二种情况,可以在第一行挖一个角,然后当前行填'***'

    如果k = 3,包括他剩下的情况,上一行都是填满的状态,可以自己构造一种简单的方案

    T2

    看标程感觉是写不出来的题,40分nq,对于每个询问,枚举n个点如果他们对一个查询点距离<=k,贡献就加1,

    但是好像数据很水,gjz nk 50000$ imes$500000过了70!

    T3

    肉眼识别了近1000组,然后就放弃了,后来才反应过来,可以跟train进行比较,然后输出嘴相似的那一幅图片

  • 相关阅读:
    053-242
    053-227
    053-671
    053-489
    053-670
    sql
    白纸黑字签字画押,出人命的事
    CSS
    JS
    Eclipse发布地址不同引发的问题
  • 原文地址:https://www.cnblogs.com/little-uu/p/14913918.html
Copyright © 2011-2022 走看看