zoukankan      html  css  js  c++  java
  • 20201003校测

    不要问我为什么今天写昨天的校测

    T1

    description:

    有N道判断题(题号编号为0~N-1),已知每道题的答案((0/1))以及答对后能获得的分数。同时还有M个额外分数。
    具体而言,每个额外分数给出四个参数(k) (i) (type) (pt)
    表示对于所有题号(j)满足(jequiv i(mod 2^k))的题目,如果这些题都选择(type(0/1)),那么会获得(pt)的额外分数

    data range;

    (N是2的整数次幂且N<=2^{20})
    (M<=10^6)

    solution:

    考虑如何维护那些奇怪的额外分数
    有一个很巧妙的方法:
    由低位向高位建01Trie,然后树上的每一个节点就恰好对应题目中的“额外分数”
    具体来讲,01Trie中深度为d,走到此处值为num就代表这些数除以(2^d)余num
    然后就是一个简单的树形dp了
    (f_{pos,0})表示pos子树内的题目全部选0可以获得的最大价值,类似定义(f_{pos,1})
    同时记(f_{pos,2})表示pos子树内的题目任意选择可以获得的最大价值
    那么就有如下转移:
    (f_{pos,0}=f_{lc,0}+f_{rc,0}+ex_{pos,0})
    (f_{pos,1}=f_{lc,1}+f_{rc,1}+ex_{pos,1})
    (f_{pos,2}=max(f_{lc,2}+f_{rc,2},f_{pos,0},f_{pos,1}))
    其中lc,rc分别表示pos的左右儿子,ex表示题目描述中的额外分数

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=(1<<20)+5;
    int n,st[N],a[N],m;
    struct _01Trie
    {
    	int dep,ch[N*21][2],tot;
    	ll f[N*21][3],ex[N*21][2];
    	void build(int pos,int d,int num)
    	{
    		if(d==dep){f[pos][2]=f[pos][st[num]]=a[num];return;}
    		ch[pos][0]=++tot;
    		build(ch[pos][0],d+1,num);
    		ch[pos][1]=++tot;
    		build(ch[pos][1],d+1,num+(1<<d));
    	}
    	inline void work()
    	{
    		dep=log2(n);
    		tot=1;build(1,0,0);
    	}
    	void upd(int pos,int nd,int d,int num,int tp,int val)
    	{
    		if(nd==d){ex[pos][tp]+=1ll*val;return;}
    		if(num&(1<<nd))upd(ch[pos][1],nd+1,d,num,tp,val);
    		else upd(ch[pos][0],nd+1,d,num,tp,val);
    	}
    	void solve(int pos,int d)
    	{
    		if(d==dep)return;
    		solve(ch[pos][0],d+1),solve(ch[pos][1],d+1);
    		f[pos][0]=f[ch[pos][0]][0]+f[ch[pos][1]][0]+ex[pos][0];
    		f[pos][1]=f[ch[pos][0]][1]+f[ch[pos][1]][1]+ex[pos][1];
    		f[pos][2]=max(f[ch[pos][0]][2]+f[ch[pos][1]][2],max(f[pos][0],f[pos][1]));
    	}
    }T;
    int main()
    {
    	scanf("%d",&n);
    	for(int i=0;i<n;++i)scanf("%d",st+i);
    	for(int i=0;i<n;++i)scanf("%d",a+i);
    	T.work();
    	scanf("%d",&m);
    	while(m--)
    	{
    		int k,i,typ,pt;scanf("%d%d%d%d",&k,&i,&typ,&pt);
    		T.upd(1,0,k,i,typ,pt);
    	}
    	T.solve(1,0);
    	printf("%lld
    ",T.f[1][2]);
    	return 0;
    }
    

    T2

    网络流(不会)

    T3

    description:

    一个(N*M)棋盘中已知每一行的棋子个数(a_i),求出在所有可能的棋局中,棋子数不少于k个的列数最少是多少

    data range;

    (N<=2*10^5) (M<=10^8)

    solution:

    考虑二分答案mid判断其是否可行
    我们尽量把前mid列全部填满,然后对于剩下的m-mid列,直接上抽屉原理
    具体来说mid值是可行的当且仅当((k-1)*(m-mid)>=x)
    其中x表示总棋子个数减去前mid列尽量填的个数(即剩下的)
    观察到(x=sum_{a_i>=mid}(a_i-mid)=sum_{a_i>=mid}a_i-mid*sum_{a_i>=mid}1)
    于是我们可以将a_i从小到大排序然后预处理后缀和check时lower_bound就可以了
    这样做的时间复杂度(O(nlog^2n))
    其实还可以再优化一点
    发现这个东西似乎和[NOI Online #1 提高组]冒泡排序里的柿子十分相似
    于是我们可以用动态开点的权值线段树类似地维护

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=2e5+5,LOG=20;
    int root,n,m,a[N];
    struct SGT
    {
    	int tot,lc[N*LOG],rc[N*LOG],c[N*LOG];LL s[N*LOG];
    	inline void up(int rt){s[rt]=s[lc[rt]]+s[rc[rt]],c[rt]=c[lc[rt]]+c[rc[rt]];}
    	void upd(int &rt,int l,int r,int p)
    	{
    		if(!rt)rt=++tot;
    		if(l==r){++c[rt],s[rt]+=1ll*l;return;}
    		int mid=(l+r)>>1;
    		if(p<=mid)upd(lc[rt],l,mid,p);
    		else upd(rc[rt],mid+1,r,p);
    		up(rt);
    	}
    	int solve(int rt,int l,int r,int k,LL sum,int cnt)
    	{
    	//	if(!rt)return 0;
    		if(l==r)return l;
    		int mid=(l+r)>>1;
    		if(sum+s[rc[rt]]-1ll*(cnt+c[rc[rt]])*mid<=1ll*(m-mid)*(k-1))
    			return solve(lc[rt],l,mid,k,sum+s[rc[rt]],cnt+c[rc[rt]]);
    		else return solve(rc[rt],mid+1,r,k,sum,cnt);
    	}
    }T;
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i)scanf("%d",a+i);
    	for(int i=1;i<=n;++i)T.upd(root,0,m,a[i]);
    	for(int i=1;i<=n;++i)printf("%d ",T.solve(root,0,m,i,0,0));
    	return 0;
    }
    
  • 相关阅读:
    [安装程序配置服务器失败]解决SQL Server2000安装失败
    C# 操作 XML 增 删 改 查
    批量修改文件的编码格式
    获取SqlServer2005表结构(字段,主键,外键,递增,描述)
    .NET 特性Attribute[一]
    windows2003远程桌面退出后系统自动注销的解决方法
    SqlServer 无日志文件附加
    接受来自服务器的数据连接时发生超时(30000 毫秒)问题原因及解决方法
    .net中数据集合导出为Excel(支持泛型及显示字段顺序,可自定义显示列名)
    EF中自编写SQL脚本查询结果(适用于复杂SQL逻辑提高查询效率)
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13767595.html
Copyright © 2011-2022 走看看