[NOI 2014]做题记录

【NOI2014】起床困难综合症

按位贪心

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 100010
using namespace std;

int n, m;
int tp[maxn], v[maxn];

int getans(int final, int p){
	for(int i = 1; i <= n; i ++){
		if(tp[i] == 0)final &= v[i];
		if(tp[i] == 1)final |= v[i];
		if(tp[i] == 2)final ^= v[i];
	}return final >> p & 1;
}

bool check(int x){
	if(getans(0, x) >= getans(1 << x, x))
		return 0;
	return 1;
}

int solve(int final){
    for(int i = 1; i <= n; i ++){
		if(tp[i] == 0)final &= v[i];
		if(tp[i] == 1)final |= v[i];
		if(tp[i] == 2)final ^= v[i];
	}return final;
}

int main(){
	scanf("%d%d", &n, &m);
	char cmd[5]; int x;
	for(int i = 1; i <= n; i ++){
		scanf("%s%d", cmd, &x);
		if(cmd[0] == ‘A‘)tp[i] = 0;
		if(cmd[0] == ‘O‘)tp[i] = 1;
		if(cmd[0] == ‘X‘)tp[i] = 2;
		v[i] = x;
	}
	int log = 1;
	for(; 1ll << log <= m; log ++);log --;
	int ans = 0;
	for(int i = log; i >= 0; i --)
		if((ans | (1 << i)) <= m && check(i))
			ans = ans | (1 << i);
	printf("%d\n", solve(ans));
	return 0;
}

【NOI2014】魔法森林

最小增量生成树

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 200010
using namespace std;  

int n, m;  

struct Edge_{
    int u, v, a, b;
    void read(){scanf("%d%d%d%d", &u, &v, &a, &b);}
    bool operator<(const Edge_& k)const{
        return a < k.a;
    }
}G[maxn];  

int L[maxn], R[maxn];
int val[maxn], c[maxn][2], fa[maxn], pos[maxn];
bool rev[maxn];  

namespace Splay{
    #define l c[x][0]
    #define r c[x][1]
    int st[maxn], top;
    void init(){
        memset(val, 0x80, sizeof val);
        for(int i = 1; i <= 2 * n; i ++)
            pos[i] = i;
    }  

    void pushup(int x){
        pos[x] = x;
        if(val[pos[x]] < val[pos[l]])
            pos[x] = pos[l];
        if(val[pos[x]] < val[pos[r]])
            pos[x] = pos[r];
    }  

    void pushdown(int x){
        if(rev[x]){
            rev[x] = 0;
            rev[l] ^= 1;
            rev[r] ^= 1;
            swap(l, r);
        }
    }  

    void rotate(int p, int x){
        int mark = p == c[x][1], y = c[p][mark ^ 1];
        int z = fa[x];
        if(x == c[z][0])c[z][0] = p;
        if(x == c[z][1])c[z][1] = p;
        if(y)fa[y] = x;
        fa[p] = z; c[p][mark ^ 1] = x;
        fa[x] = p; c[x][mark] = y;
        pushup(x);
    }  

    bool isroot(int p){
        return c[fa[p]][0] != p && c[fa[p]][1] != p;
    }  

    void splay(int p){
        st[top = 1] = p;
        for(int i = p; !isroot(i); i = fa[i])
            st[++ top] = fa[i];
        for(;top; top --)
            pushdown(st[top]);  

        while(!isroot(p)){
            int x = fa[p], y = fa[x];
            if(isroot(x))rotate(p, x);
            else if(p == c[x][0] ^ x == c[y][0])
                rotate(p, x), rotate(p, y);
            else rotate(x, y), rotate(p, x);
        }
        pushup(p);
    }
    #undef l
    #undef r
}  

namespace LCT{
    void Access(int u){
        int t = 0;
        while(u){
            Splay::splay(u);
            c[u][1] = t;
            t = u;
            u = fa[u];
        }
    }  

    void Evert(int u){
        Access(u);
        Splay::splay(u);
        rev[u] ^= 1;
    }  

    void link(int u, int v, int t){
        Evert(v);
        fa[v] = t;
        Evert(t);
        fa[t] = u;
    }  

    void cut(int u, int v, int t){
        Evert(t);
        Access(u);
        Splay::splay(u);
        c[u][0] = fa[t] = 0;
        Evert(t);
        Access(v);
        Splay::splay(v);
        c[v][0] = fa[t] = 0;
    }  

    int find(int u){
        Access(u);
        Splay::splay(u);
        while(c[u][0])u = c[u][0];
        return u;
    }  

    int ask(int u, int v){
        if(find(u) != find(v))
            return -1;
        Evert(u);
        Access(v);
        Splay::splay(v);
        return pos[v];
    }
}  

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i ++)
        G[i].read();
    sort(G + 1, G + 1 + m);
    Splay::init();
    int ans = 0x7fffffff;
    int cnt = n;
    for(int i = 1; i <= m; i ++){
        int t = LCT::ask(G[i].u, G[i].v);
        if(t == -1){
            t = ++ cnt;
            L[t] = G[i].u;
            R[t] = G[i].v;
            val[t] = G[i].b;
            fa[t] = c[t][0] = c[t][1] = 0;
            pos[t] = t;
            LCT::link(L[t], R[t], t);
        }
        else if(val[t] > G[i].b){
            LCT::cut(L[t], R[t], t);
            L[t] = G[i].u;
            R[t] = G[i].v;
            val[t] = G[i].b;
            fa[t] = c[t][0] = c[t][1] = 0;
            pos[t] = t;
            LCT::link(L[t], R[t], t);
        }
        t = LCT::ask(1, n);
        if(t != -1)
            ans = min(ans, val[t] + G[i].a);
        //cout << ans << ‘ ‘ << val[t] << ‘ ‘ << G[i].a << ‘ ‘ << G[i].b << endl;
    }  

    if(ans > 1000000)
        ans = -1;
    printf("%d\n", ans);  

    return 0;
}

【NOI2014】动物园

KMP

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 1000010
#define mod 1000000007ll
using namespace std;

int nxt[maxn], n;

char c[maxn];

int p[maxn];

long long ans;
void solve(){
	p[1] = 1;
	nxt[0] = nxt[1] = 0;
	for(int i = 2; i <= n; i ++){
		int j = nxt[i - 1];
		while(j && c[i] != c[j + 1])j = nxt[j];
		if(c[i] == c[j + 1])j ++;
		nxt[i] = j;
		p[i] = p[j] + 1;
	}

	int j = 0;
	ans = 1;
	for(int i = 2; i <= n; i ++){
		while(j && c[i] != c[j + 1])j = nxt[j];
		if(c[i] == c[j + 1])j ++;
		while(j * 2 > i)j = nxt[j];
		ans = 1ll * (p[j] + 1) * ans % mod;
	}
	printf("%lld\n", ans);
}

int main(){
	int test;
	scanf("%d", &test);
	while(test --){
		scanf("%s", c + 1);
		n = strlen(c + 1);
		solve();
	}
	return 0;
}

【NOI2014】随机数生成器

把序列搞出来每次取最小值看是否可以添加进去

每一行可取的范围是连续的,维护Li和Ri就可以判定

#include <algorithm>
#include <stdio.h>
typedef long long ll;
int x0, a, b, c, d;
int n, m, q;
int T[25000001], mp[5001][5001];
int l[5001], r[5001];
int Rand(){
	x0 = ((ll)a * x0 * x0 % d + (ll)b * x0 + c) % d;
	return x0;
}

int main(){
	scanf("%d%d%d%d%d", &x0, &a, &b, &c, &d);
	scanf("%d%d%d", &n, &m, &q);
	int k = n * m;
	for(int i = 1; i <= k; i ++)
	    T[i] = i;

	for(int i = 1; i <= k; i ++)
	    std::swap(T[i], T[Rand() % i + 1]);
	int x, y;
	for(int i = 1; i <= q; i ++)
	    scanf("%d%d", &x, &y), std::swap(T[x], T[y]);

	int nw = 0;
	for(int i = 1; i <= n; i ++)
	    for(int j = 1; j <= m; j ++)
	        mp[i][j] = T[++ nw];
	for(int i = 1; i <= n; i ++)
	    for(int j = 1; j <= m; j ++)
	        T[mp[i][j]] = i << 16 | j;
	for(int i = 1; i <= n; i ++)
	    l[i] = 1, r[i] = m;
	bool flag = false;
	for(int i = 1; i <= k; i ++){
		x = T[i] >> 16;
		y = T[i] & 65535;
		if(l[x] <= y && y <= r[x]){
			if(flag)putchar(‘ ‘);
			flag = true;
			printf("%d", i);
			for(int j = 1; j < x; j ++)r[j] = std::min(r[j], y);
			for(int j = x + 1; j <= n; j ++)l[j] = std::max(l[j], y);
		}
	}
	return 0;
}

【NOI2014】购票

树剖+三分

long long 乘 long long乘爆了。。

改成double才过

凸包不要建错

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#define maxn 200010
using namespace std;
typedef long long ll;
int n;
struct Edge{
	int to, nxt;
	ll dis;
}edge[maxn];

int h[maxn], cnt;
void add(int u, int v, ll d){
	edge[++ cnt] = (Edge){v, h[u], d};
	h[u] = cnt;
}

const ll inf = 1ll << 60;
const int root = 1;
ll p[maxn], q[maxn], L[maxn], dis[maxn], dp[maxn];

int fa[maxn], anc[maxn][20];
int top[maxn], son[maxn], pos[maxn], size[maxn], dfs_clock;

void dfs1(int u){
	size[u] = 1;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa[u])continue;
		anc[v][0] = fa[v] = u;
		dis[v] = dis[u] + edge[i].dis;
		dfs1(v);
		size[u] += size[v];
		if(size[v] > size[son[u]])
		    son[u] = v;
	}
}

void dfs2(int u, int tp){
	pos[u] = ++ dfs_clock;
	top[u] = tp;
	if(son[u])dfs2(son[u], tp);
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa[u] || v == son[u])continue;
		dfs2(v, v);
	}
}

int Find(int u, ll d){
	for(int i = 18; i >= 0; i --)
	    if(dis[anc[u][i]] >= d)
	        u = anc[u][i];
	return u;
}

#define lc id << 1
#define rc id << 1 | 1
vector<int> t[maxn << 2];

void update(int id, int l, int r, int u){
	int top = t[id].size() - 1;
	while(top > 0){
		int t1 = t[id][top], t2 = t[id][top - 1];
		if((double)(dp[u] - dp[t1]) / (dis[u] - dis[t1]) < (double)(dp[u] - dp[t2]) / (dis[u] - dis[t2]))
	    	top --, t[id].pop_back();
		else break;
	}
	t[id].push_back(u);
	if(l == r)return;
	int mid = l + r >> 1;
	if(pos[u] <= mid)update(lc, l, mid, u);
	else update(rc, mid+1, r, u);
}

ll pd(int i, int u){return dp[i] + (dis[u] - dis[i]) * p[u] + q[u];}

ll check(int id, int u){
	int l = 0, r = t[id].size() - 1;
	ll ret = inf;
	while(r - l >= 3){
		int m1 = (l + l + r) / 3, m2 = (l + r + r) / 3;
		if(pd(t[id][m1], u) > pd(t[id][m2], u))
		    l = m1;
		else r = m2;
	}
	for(int i = l; i <= r; i ++)
	    ret = min(ret, pd(t[id][i], u));
	return ret;
}

ll ask(int id, int l, int r, int L, int R, int u){
	if(l == L && r == R)return check(id, u);
	int mid = l + r >> 1;
	if(R <= mid)return ask(lc, l, mid, L, R, u);
	if(L > mid) return ask(rc, mid+1, r, L, R, u);
	return min(ask(lc, l, mid, L, mid, u), ask(rc, mid+1, r, mid+1, R, u));
}

ll query(int u){
	ll d = dis[u] - L[u], ret = inf;
	int nw = u; u = fa[u];
	while(u){
		if(dis[u] < d)break;
		int l = pos[top[u]], r = pos[u];
		if(dis[top[u]] < d)l = pos[Find(u, d)];
		ret = min(ret, ask(1, 1, n, l, r, nw));
		u = fa[top[u]];
	}return ret;
}

void solve(int u){
	if(u != 1)dp[u] = query(u);
	update(1, 1, n, u);
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa[u])continue;
		solve(v);
	}
}

int main(){
	int test;
	scanf("%d%d", &n, &test);
	int f; ll s;
	for(int i = 2; i <= n; i ++){
		scanf("%d%lld%lld%lld%lld", &f, &s, &p[i], &q[i], &L[i]);
		add(f, i, s);
	}
	dfs1(root);
	dfs2(root, root);
	for(int j = 1; 1 << j <= n; j ++)
		for(int i = 1; i <= n; i ++)
		    anc[i][j] = anc[anc[i][j-1]][j-1];
	solve(root);
	for(int i = 2; i <= n; i ++)
	    printf("%lld\n", dp[i]);
	return 0;
}

  

时间: 2024-10-31 18:46:54

[NOI 2014]做题记录的相关文章

清华集训2014 做题记录

清华集训2014做题记录 已完成 [清华集训2014]玛里苟斯 [清华集训2014]主旋律 [清华集训2014]奇数国 [清华集训2014]矩阵变换 [清华集训2014]sum [清华集训2014]虫逢 [清华集训2014]玄学 [清华集训2014]文学 未完成 [清华集训2014]卡常数 [清华集训2014]简单回路 [清华集训2014]Router [清华集训2014] Breaking Bomber 写一题要膜一题题解,膜完题解膜代码,膜完代码膜指导,膜了好几天了还有四个题没做. [清华集

【BZOJ做题记录】07.07~?

在NOI一周前重开一个坑 最后更新时间:7.07 11:26 7.06 下午做的几道CQOI题: BZOJ1257: [CQOI2007]余数之和sum:把k mod i写成k-k/i*i然后分段求后面的部分就好了 BZOJ1258: [CQOI2007]三角形tri:在草稿纸上按照位置和边找一下规律就好了 BZOJ1260: [CQOI2007]涂色paint:简单的区间DP BZOJ1303: [CQOI2009]中位数图:小于中位数的改为-1大于的改为1,算一算前缀和然后哈希一下乘一乘就好

后缀自动机做题记录

目录 后缀自动机做题记录 sp1811 sp1812 sp10570 luogu 2463 CF873F TJOI2015 弦论 AHOI2013 差异 HEOI2016/TJOI2016 字符串 HAOI2016 找相同字符 SDOI2016 生成魔咒 ZJOI2015 诸神眷顾的幻想乡 留坑待填 广义SAM 其他 NOI原题练习 后缀自动机做题记录 来填之前的坑了...考后大概会做做有字符串的综合题吧 sp1811 lcs板子,对于第一个串建出SAM,第二个串在上面跑,即可求出对于每一个位置

project euler做题记录

ProjectEuler_做题记录 简单记录一下. problem 441 The inverse summation of coprime couples 神仙题.考虑答案为: \[\begin{array}{c} S(n) & = & \sum_{i = 1} ^ n \sum_{p = 1} ^ i \sum_{q = p + 1} ^ i \frac {1}{pq}[p + q \geq i][gcd(p, q) = 1] \& = & \sum_{i = 1} ^

退役前的做题记录5.0

退役前的做题记录5.0 出于某种原因新开了一篇. [CodeChef]Querying on a Grid 对序列建立分治结构,每次处理\((l,mid,r)\)时,以\(mid\)为源点建立最短路树,这样跨越\(mid\)的点对之间的最短路一定会经过\(mid\),因此两点之间的最短路径就可以描述成最短路树上的两段到根路径.对每棵最短路树处理\(dfs\)序,用树状数组维护权值修改即可. [Wannafly挑战赛4F]线路规划 类似SCOI2016萌萌哒一题,并查集\(f_{i,j}\)表示从

2020年3月做题记录

[不定时更新,赶论文,赶项目,1月~2月做题记录还在整理,自我训练] 反转链表 链接:https://leetcode-cn.com/problems/reverse-linked-list/ 类名: 考察点:链表.迭代.递归 解题过程: 力扣3月每日1题,题解链接: https://leetcode-cn.com/problems/reverse-linked-list/solution/di-2ci-da-qia-lian-biao-fan-zhuan-di-gui-by-wu-xi-/ 就

2017雅礼省选集训做题记录

嘛,最近在补雅礼省选前集训的题.都是我会做的题..那一定是最水的那些题啦 题目在loj.ac上都有.过段时间如果搬了雅礼NOI集训的题应该也会做做的吧.. Day1 T1 一道经典套路题,做法跟UOJ #228基础数据结构练习题类似. 使用线段树维护.考虑相邻两个数的差值最多变化log次.也就是说,对于每个区间,只要操作二进行大概log次就能使得这个区间内所有数完全一样.所以对于操作二,只要记录一下区间最大最小值,就能直接打标记或者暴力DFS下去. 和UOJ那个题一样,注意一个特殊情况,就是一个

Educational Codeforces Round 79做题记录

这套题感觉出的不咋滴,第四题和第五题难度差了1000分!!! 前四题都还简单,第五题就31人做出……我算了…… 懒得写题解了,做个记录吧(这就是偷懒的理由???) 比赛传送门 A.New Year Garland 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #define re

2020年3月底到4月第1周做题记录(力扣)

写在前面的话: 多看书,整完论文,deadline驱动,加油. 做题时间: 2020年3月30日~2020年4月5日 记录: 总共道题,时间为min. 最近更新时间: 202003230 圆圈中最后剩下的数字 链接: https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/ 类名: 考察点: 环.模拟 解题过程:力扣3月每日1题 题目的意思是用n个数字形成一个圆圈,数字范围为0到n-1,数