• NEERC Southern Subregional 2012


    NEERC Southern Subregional 2012

    Problem B. Chess Championship

    题目描述:有两个序列(a, b),两个序列都有(n)个数,并且这(2n)个数两两不同,现在要将这两个序列里的数两两配对,组成(n)个数对,要求数对中(a)的数比(b)的数大的数对个数要比其它的多(m)个。问方案数。

    solution
    将这(2n)个数从小到大排,预处理出前(i)个数中(a, b)的个数(suma, sumb), (f[i][j][k])表示前(i)个数,匹配了(j)(a>b)的数对,还有(k)(a)未匹配。
    如果第(i)个数是(a)的数:

    1. 与前面的一个还没有匹配的(b)匹配,(f[i+1][j+1][k]+=f[i][j][k]*(sumb[i-1]-suma[i-1]+k))
    2. 留着让后面的(b)匹配,(f[i+1][j][k+1]+=f[i][j][k])
      如果第(i)个数是(b)的数:
    3. 与前面一个还没有匹配的(a)匹配,(f[i+1][j][k-1]+=f[i][j][k]*k)
    4. 留着让后面的(a)匹配,(f[i+1][j][k]+=f[i][j][k])

    答案就是(f[2*n+1][0][0]),因为空间不够,所有要有滚动数组,而且卡常,所以要控制好枚举的范围。

    时间复杂度:(O(n^3))

    Problem E. Dragons and Princesses

    题目描述:有(n)个格子,每个格子上有一条龙或一个公主,每条龙守着一定数量的金币,现在要从第一个格子出发,遇到龙时可以选择跳过,也可以选择杀死龙并拿走金币,如果遇到公主,假如杀龙的数量大于等于公主的要求,那么就要娶这个公主,已知最后一个格子是一个公主,并且娶且只娶最后一个公主,问最多能拿多少金币,输出方案。

    solution
    首先从后往前,算出到达每个格子时最多能杀多少条龙,然后用一个堆维护最大的那几条龙即可。

    时间复杂度:(O(nlogn))

    Problem F. Dumbbells

    题目描述:有(n)个球,每个球的重量为(w_i),价值为(c_i),现在要取尽量多的集合,每个集合必须要有(k)个球,并且(k)个球的重量不同,而且每个集合的重量集合必须相同。问在最多能构成多少个集合,并且最大价值为多少。

    solution
    统计每种重量的球有多少,从大到小排序,然后取前(k)种重量,对应的集合数为第(k)中重量的球的个数(s),然后算出球数大于等于(s)的重量中每种重量的最贵的(s)个球的总价值,然后取价值最大的(k)中重量。

    时间复杂度:(O(nlogn))

    Problem G. Database optimization

    题目描述:有(n)个物品,每个物品有不超过(4)种性质,有(m)个询问,每次询问拥有某些性质的物品有多少。

    solution
    性质的集合不超过(n*2^4)种,预处理出这些集合各有多少个物品拥有即可,用一个(map)就好了。

    时间复杂度:(O(2^4n+m))

    Problem H. Sultan's Pearls

    题目描述:有一串珠子放在桌上,一共有(n)个珠子,其中有(m)个悬在桌边,每个珠子有重量和价值,现在一次可以从两边取一个珠子(桌上或悬挂),如果取的是悬挂的珠子,则要从桌上移一个珠子使悬挂的珠子总数不变,当悬挂的珠子的总重量大于桌上的珠子的总重量乘(k)时,珠子会掉下来,问在保证珠子不掉下来的情况下,能拿走的最大总价值,输出方案。

    solution
    方案显然是先拿走悬挂的,然后再拿在桌上的。所以可以枚举最终悬挂的珠子的最下面一个是哪个,然后二分出桌面上最多能拿走多少个珠子,然后贪心地拿就好。

    时间复杂度:(O(nlogn))

    Problem J. Ternary Password

    题目描述:有一个只有(0, 1, 2)的字符串,现在可以修改某些位置的字符,使得最终有(a)(0)(b)(1),问最少需要修改多少个字符,并且输出修改后的字符串。

    solution
    贪心。

    时间复杂度:(O(n))

    Problem K. Tree Queries Online

    题目描述:给定一棵树,树有边权,不断地删掉一条边,输出删掉的边的权值(val),取出分开的两棵树中点数较少的树(如果相同则取最小编号的点所在的树),这棵树的边权乘(val),另一棵树的边权加(val)。强制在线。

    solution
    启发式拆树,拆的时候同时扩展两棵树,有一棵树搜完就停下,然后把这棵树的边权暴力更新,新建一个集合存这些点,旧的集合存另外一棵树,在旧集合打上边权增量标记。

    时间复杂度:(O(nlogn))

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int mod=99990001;
    const int maxn=int(2e5)+100;
    
    struct LINK
    {
    	int id, pre, next;
    };
    
    int n, now;
    int h[maxn], nx[maxn];
    LINK t[maxn*2];
    int block[maxn];
    int blockcnt;
    LL ans[maxn], mark[maxn];
    queue<int> q[2];
    int edge[2][maxn];
    bool vis[maxn];
    
    void join(int u, int v)
    {
    	t[now].id=v; t[now].next=h[u]; t[now].pre=-1; if (h[u]!=-1) t[h[u]].pre=now; h[u]=now++;
    	t[now].id=u; t[now].next=h[v]; t[now].pre=-1; if (h[v]!=-1) t[h[v]].pre=now; h[v]=now++;
    }
    void read()
    {
    	scanf("%d", &n);
    	for (int i=1; i<=n; ++i) h[i]=-1;
    	for (int i=1; i<n; ++i)
    	{
    		int u, v, w;
    		scanf("%d%d%d", &u, &v, &w);
    		join(u, v);
    		ans[i]=w;
    	}
    }
    void bfs(int u, int v, int blockidx, LL w)
    {
    	int minidx[2]={u, v};
    	edge[0][0]=edge[1][0]=0;
    	nx[u]=h[u]; nx[v]=h[v];
    
    	while (!q[0].empty()) q[0].pop();
    	while (!q[1].empty()) q[1].pop();
    	q[0].push(u); q[1].push(v);
    
    	while (!q[0].empty() && !q[1].empty())
    	{
    		for (int j=0; j<2; ++j)
    		{
    			int cur=q[j].front();
    			bool flag=false;
    
    			for (int i=nx[cur]; i>-1; i=nx[cur]=t[i].next)
    				if (!vis[i/2+1])
    				{
    					flag=true;
    					minidx[j]=min(minidx[j], t[i].id);
    					q[j].push(t[i].id);
    					edge[j][++edge[j][0]]=i/2+1;
    					nx[t[i].id]=h[t[i].id];
    					vis[i/2+1]=true;
    					nx[cur]=t[i].next;
    					break;
    				}
    			if (!flag) q[j].pop();
    		}
    	}
    
    	int idx=0;
    	if ((!q[0].empty() && q[1].empty()) || (q[0].empty() && q[1].empty() && minidx[1]<minidx[0])) idx=1;
    
    	++blockcnt;
    	for (int i=1; i<=edge[idx][0]; ++i)
    	{
    		ans[edge[idx][i]]=(ans[edge[idx][i]]+mark[blockidx])*w%mod;
    		block[edge[idx][i]]=blockcnt;
    	}
    	mark[blockidx]=(mark[blockidx]+w)%mod;
    
    	for (int j=0; j<2; ++j)
    		for (int i=1; i<=edge[j][0]; ++i) vis[edge[j][i]]=false;
    }
    void edge_del(int idx)
    {
    	for (int cur=idx*2-2; cur<idx*2; ++cur)
    	{
    		if (t[cur].pre!=-1) t[t[cur].pre].next=t[cur].next;
    		else h[t[cur^1].id]=t[cur].next; 
    		if (t[cur].next!=-1) t[t[cur].next].pre=t[cur].pre;
    	}
    }
    void solve()
    {
    	blockcnt=1;
    	for (int i=1; i<n; ++i) block[i]=1;
    
    	for (int i=1; i<n; ++i)
    	{
    		int idx;
    		scanf("%d", &idx);
    		printf("%lld
    ", (ans[idx]=(ans[idx]+mark[block[idx]])%mod));
    		fflush(stdout);
    		edge_del(idx);
    		bfs(t[(idx-1)*2].id, t[idx*2-1].id, block[idx], ans[idx]);
    	}
    }
    int main()
    {
    	read();
    	solve();
    	return 0;
    }
    

    Problem L. Preparing Problem

    solution
    仔细算一下就好了。

    时间复杂度:(O(1))

  • 相关阅读:
    Python2和3的区别
    Linux内核的中断机制
    Linux内核的并发与竞态、信号量、互斥锁、自旋锁
    驱动程序实例(五):LCD驱动程序分析(Samsung LCD)
    Linux字符设备驱动框架(五):Linux内核的framebuffer驱动框架
    驱动程序实例(四):按键驱动程序(platform + input子系统 + 外部中断方式)
    Linux字符设备驱动框架(四):Linux内核的input子系统
    gpiolib库详解
    Linux字符设备驱动框架(三):Linux内核的misc类设备驱动框架
    驱动程序实例(三):蜂鸣器驱动程序(misc类设备驱动框架)
  • 原文地址:https://www.cnblogs.com/GerynOhenz/p/9919818.html
Copyright © 2020-2023  润新知