• [NOIP11.1模拟赛]补番报告


    Preface

    昨天开始补某科学的超电磁炮S 感觉今天就好了点,炮姐赛高

    T1 一开始一直想欧拉定理&ex欧拉定理,结果估计70分,数组开小了GG,看了正解发现是我学傻了

    T2 一看就是数据结构,之前某次模拟还做过区间位运算线段树但是不敢打,只敲了个前缀和预计50结果有个地方没膜GG

    T3 想了蛮久,很有意思的一道题目,考场上画了图发现我们可以将放坐标的那个点看成树根,这样它覆盖了一条近似链的玩意,想搞波DP发现不会,于是打了个骗分的玩意,就是我猜和节点的儿子个数有关,我直接用儿子个数除2向上取整结果...OJ上15,source里30.发现ZZ地没判点的情况,然后发现更ZZ的是我特意判了链的情况,但是我输出的是0

    10分就这么走了GG

    T1 pow

    学傻了的我一直想欧拉定理...结果solution告诉你只要会快速幂就可以A这题了

    a既然是定值我们就分块打表啊

    由于b最大是1e12,按1e6拆分.

    预处理出({a^1}... {a^{1e6}}),丢进一个数组,在预处理出(a^{i imes 1e6}),丢进另外一个数组

    这样所有的b都能拼出来了

    还是比较妙的,这告诉我们有的时候去搞旧算法不如想新trick

    代码

    const int maxn=1000005;
    const int inf = 0x7fffffff;
    ll a,q,k;
    ll b,l,m,c,p;
    ll pre[maxn][2],sum[10000005];
    inline ll ksm(ll aa,ll cc){
    	ll ans=1;
    	while(cc){
    		if(cc&1)ans=ans*a%p;
    		aa=aa*aa%p;
    		cc=cc>>1;
    	}
    	return ans;
    }
    int main(){
    	FI(pow)FO(pow)
    	read(a),read(p),read(q),read(k);
    	read(b),read(l),read(m),read(c);
    	pre[0][0]=1;
    	for(ri i=1;i<=1000000;i++){
    		pre[i][0]=pre[i-1][0]*a%p;
    	}
    	pre[1][1]=pre[1000000][0];
    	for(ri i=2;i<=1000000;i++){
    		pre[i][1]=pre[i-1][1]*pre[1][1]%p;
    	}
    	for(ri i=1;i<=q;i++){
    		b=(b*m+c)%l;
    		if(b<=1000000)sum[i]=sum[i-1]^pre[b][0];
    		else {
    			ll id=b/1000000;
    			sum[i]=sum[i-1]^((pre[b%1000000][0]*pre[id][1])%p);
    		}
    	}
    	int kk=k;
    	while(kk<=q){
    		printf("%lld
    ",sum[kk]);
    		kk+=k;
    	}
    	return 0;
    }
    
    

    T2 seg

    英文是seg 中文是tree 就是告诉你用线段树(segment tree)啦

    对于区间按位与操作,类比区间取膜的时间复杂度分析(给学弟讲过结果自己还忘了)

    每个数最多操作31次,n只有1e5,因此是资瓷的

    我们只要维护一个区间按位或判断需不需要修改就好了,其余情况暴力递归修改

    2操作就trival了,会线段树的都会

    3操作也比较正常,你可以先思考部分分怎么拿,你把这个期望平方和(实际上这个式子就是(sum_{i=l}^r (a_i+a_j)^2 (j=l,l+1...r)))大力展开

    发现维护一个区间平方和和区间和就好了

    然后有个神坑的地方

    就是在判断是否要按位与时的位运算的优先级

    if((or_sum[now]&(~dta))==0)return ;

    if(or_sum[now]&(~dta)==0)return ;

    请您判断上面哪个是对的

    答案是第一个,但是你写第二个不会对答案正确性产生影响,但是每次它都会递归下去修改使得时间复杂度大大提高

    可见位运算优先级之低

    代码

    const int maxn=100005;
    const int inf=0x7fffffff;
    const int P=998244353;
    int a[maxn],n,q;
    ll sum[maxn<<2];
    int eq_sum[maxn<<2];
    int or_sum[maxn<<2];
    inline void up(int now){
    	sum[now]=sum[now<<1]+sum[now<<1|1];
    	eq_sum[now]=(eq_sum[now<<1]+eq_sum[now<<1|1]);
    	if(eq_sum[now]>P)eq_sum[now]-=P;
    	or_sum[now]=or_sum[now<<1]|or_sum[now<<1|1];
    	return ;
    }
    void build(int now,int l,int r){	
    	if(l==r){
    		or_sum[now]=sum[now]=a[l];
    		eq_sum[now]=1ll*a[l]*a[l]%P;
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(now<<1,l,mid);
    	build(now<<1|1,mid+1,r);
    	up(now);return ;
    }
    int dta,t,L,R;
    void update(int now,int l,int r){
    	if((or_sum[now]&(~dta))==0)return ;//运算符顺序!!! 
    	if(l==r){
    		a[l]=a[l]&dta;
    		or_sum[now]=sum[now]=a[l];
    		eq_sum[now]=1ll*a[l]*a[l]%P;
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(L<=mid)update(now<<1,l,mid);
    	if(mid<R)update(now<<1|1,mid+1,r);
    	up(now);return ;
    }
    ll ans1=0,ans2=0;
    void query(int now,int l,int r){
    	if(L<=l&&r<=R){
    		ans1+=sum[now];
    		ans2=(ans2+eq_sum[now]);
    		if(ans2>P)ans2-=P;
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(L<=mid)query(now<<1,l,mid);
    	if(mid<R)query(now<<1|1,mid+1,r);
    	return ;
    }
    int main(){
    	int x,y,opt;
    	FO(seg)
    	//freopen("seg6.in","r",stdin);
    	//freopen("wtf.out","w",stdout);
    	read(n);
    	for(ri i=1;i<=n;i++)read(a[i]);
    	build(1,1,n);
    	read(q);
    	while(q--){
    		read(opt),read(L),read(R);
    		ans1=ans2=0;
    		if(opt==1){
    			read(dta);
    			update(1,1,n);
    		}
    		if(opt==2){
    			query(1,1,n);
    			printf("%lld
    ",ans1);
    		}
    		if(opt==3){
    			query(1,1,n);
    			ans1=ans1%P;
    			printf("%lld
    ",(((ans2<<1)%P*(R-L+1)%P+(ans1<<1)*ans1%P))%P);
    		}
    	}
    	return 0;
    }
    
    

    T3 beacon

    一道Topcoder上有趣的题目

    我是这么想的,除了一点之外的情况,答案肯定是大与等于1的,我们不妨先钦定一个点,在上面放一个信标,然后以它为根遍历整棵树,显然此时深度相同的点都是非法的

    考虑这种情况:有两个兄弟叶节点,那么它们此时是非法的,显然在除这两个叶节点之外的任何一点放置信标这两点还是非法的(它们的深度还是相同),所以我们必须在这两个叶子节点之一放一个信标

    稍微拓展一下:假若有三个兄弟叶节点,那么类似的发现你必须在三个叶节点中放两个信标才可以;于是归纳假设发现对于n个兄弟叶节点你必须在之中放n-1个信标

    那么对于不是叶节点的点呢?你会发现这时候它们似乎都已经是合法的了

    除了链的情况,链的情况下由于最底端只有一个叶子节点不会统计答案,但是实际上你会发现链实际上整体就可以看做一个叶节点处理.

    于是按照上面的步骤(O(N^2))就好了

    满分做法看不懂,这里给出题解,不知哪位大佬可以帮忙解释一下

    如何做到 O(n)? 我们先特判链的情况答案为 1, 然后找到任意一个度数大于 2 的节点, 可以证
    明这个点一定不需要放置信标. 于是以这个点作根 O(n) 的贪心即可. 证明如下:
    深度相同的点对证明同上, 只考虑深度不同的点对. 如果它们在一颗子树中, 由于度数大于 2 所
    以一定有另一颗子树的一个信标把他们区分开. 如果在不同的子树中, 有两种情况:
    一个在没放信标的子树中, 一个在放了的子树中. 显然还存在另一个子树放了信标, 由于深度不
    同他们会被这个信标区分开.
    两个都在放了信标的子树中. 如果根的度数大于 3 则同上. 度数等于 3 时, 如果他们没有被区分
    开, 一定是他们先汇集到了一个节点上, 然后走到同一个信标上. 这个点一定是一条奇链的中点, 且
    不是根 (由于深度不同), 是在两个子树之一中唯一的. 那么他们走到另一个信标就一定有一个点走
    了冤枉路, 既另一个信标可以区分出他们

    70分代码

    const int maxn=1000005;
    const int inf=0x7fffffff;
    int n;
    struct Edge{
    	int ne,to;
    }edge[maxn<<1];
    int h[maxn],num_edge=1;
    inline void add_edge(int f,int to){
    	edge[++num_edge].ne=h[f];
    	edge[num_edge].to=to;
    	h[f]=num_edge;
    }
    int ans=inf,sum=0;
    bool is_lef[maxn],on_chain[maxn];
    void dfs(int now,int fa){
    	int v,cnt=0,tot=0;
    	is_lef[now]=0,on_chain[now]=0;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(v==fa)continue;
    		is_lef[now]=1,tot++;
    		dfs(v,now);
    		if(!is_lef[v]||on_chain[v])cnt++;
    	}
    	if(tot==1&&cnt==1)on_chain[now]=1;
    	if(cnt>1)sum+=cnt-1;
    	return ;
    }
    int deg[maxn];
    int main(){
    	int x,y;
    	//FO(beacon)
    	read(n);
    	if(n==1){puts("0");return 0;}
    	for(ri i=1;i<n;i++){
    		read(x),read(y);
    		add_edge(x,y),add_edge(y,x);
    	}
    	for(ri rt=1;rt<=n;rt++){
    		sum=0;
    		dfs(rt,0);
    		ans=min(ans,sum+1);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    wget(转)
    852. Peak Index in a Mountain Array
    617. Merge Two Binary Trees
    814. Binary Tree Pruning
    657. Judge Route Circle
    861. Score After Flipping Matrix
    832. Flipping an Image
    461. Hamming Distance
    654. Maximum Binary Tree
    804. Unique Morse Code Words
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9892335.html
Copyright © 2020-2023  润新知