2021杭电多校补题——第一场

2021杭电多校补题——第一场


Mod, Or and Everything

题目链接——HDU 6950


题意:
T T T 组测试数据,每组给出一个整数 n n n ,求 ( n   m o d   n )   ∣   ( n   m o d   ( n − 1 )   ∣   ( n   m o d   ( n − 2 ) ) . . .   ∣   ( n   m o d   2 )   ∣   ( n   m o d   1 ) ) (n\ mod\ n) \ |\ (n\ mod\ (n-1)\ | \ (n\ mod\ (n-2))...\ |\ (n\ mod\ 2)\ |\ (n\ mod\ 1)) (n mod n)  (n mod (n1)  (n mod (n2))...  (n mod 2)  (n mod 1)),其中" ∣ | "表示位运算或

题解:
可以发现从从 n % n n\%n n%n 开始,取模结果依次为 0 、 1 、 2 、 3... 、 ⌊ n − 1 2 ⌋ 、 . . . 0 0、1、2、3...、\lfloor\frac {n-1} {2}\rfloor、...0 0123...2n1...0,即包含了 0 0 0~ ⌊ n − 1 2 ⌋ \lfloor\frac {n-1} {2}\rfloor 2n1 所有数,由此可推得答案为 2 k − 1 2^k-1 2k1 ,其中 2 k 2^k 2k 是第一个大于 ⌊ n − 1 2 ⌋ \lfloor\frac {n-1} {2}\rfloor 2n1 的二次幂

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<algorithm>
#include<cstdio>
#include<list>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#define int long long
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))
const int mod = 1e9+7;
using namespace std;
inline int read(){
	char c=getchar();int x=0,s=1;
	while(c<'0'||c>'9'){if(c=='-')s=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*s;
}
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
#define endl '\n'
const int INF = 0x3f3f3f3f;
const int N = 1e6+10;
const int maxn = 1e3+10;

signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int t; cin>>t;
	while(t--){
		int n; cin>>n;
		n=(n-1)/2;
		int ans=1;
		while(ans<=n)ans<<=1;
		cout<<ans-1<<endl;
	}
}


Rocket land(待补)

题目链接——HDU 6951


.
.
.


Puzzle loop(待补)

题目链接——HDU 6952


.
.
.


Another thief in a Shop(待补)

题目链接——HDU 6953


.
.
.


Minimum spanning tree

题目链接——HDU 6954


题意:
T T T 组测试数据,每组给出一个整数 n n n 表示图中有 n − 1 n-1 n1 个点,每个点的权值分别为 2 2 2 ~ n n n ,在顶点 a a a 和顶点 b b b 之间连一条边的代价是 l c m ( a , b ) lcm(a,b) lcm(a,b) ,计算将所有点连成一颗树的最小代价

题解:
简单贪心,每个合数顶点都连在自己的最小质因数上,质数顶点连在顶点 2 2 2 上就行了

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<algorithm>
#include<cstdio>
#include<list>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#define int long long
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))
const int mod = 1e9+7;
using namespace std;
inline int read(){
	char c=getchar();int x=0,s=1;
	while(c<'0'||c>'9'){if(c=='-')s=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*s;
}
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
#define endl '\n'
const int INF = 0x3f3f3f3f;
const int N = 1e7+10;
const int maxn = 1e3+10;
bool vis[N];
int prime[N],cnt;
int ans[N];
void get_prime(){
	vis[1]=1;
    for(int i=2;i<=N;++i){
        if(vis[i]==0) {
            prime[++cnt]=i;
        }
        for(int j=1;j<=cnt&&prime[j]*i<=N;++j) {
            vis[i*prime[j]]=true;
            if(i%prime[j]==0)
                break;
        }
    }
} 
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	get_prime();
	for(int i=3;i<=N;i++){
        if(vis[i]==0)ans[i]=ans[i-1]+i*2;//质数结点连在顶点2上,代价为2*i
        else ans[i]=ans[i-1]+i;//合数结点连在最小质因数上,代价为i
    }
	int t; cin>>t;
	while(t--){
		int n; cin>>n; 
		cout<<ans[n]<<endl;
	}
}


Xor sum

题目链接——HDU 6955


题意:
T T T 组测试数据,每组第一行给出两个整数 n 、 k n、k nk,接下来一行 n n n 个整数,求 L , R L,R LR 满足 a [ L ] ⨁ a [ L + 1 ] . . . ⨁ a [ R ] ≤ k a[L]\bigoplus a[L+1]...\bigoplus a[R]\le k a[L]a[L+1]...a[R]k,若答案有多个则输出左端点最小的 L   R L\ R L R,若没有答案则输出 − 1 -1 1

题解:
这题想了好久了,一直没想明白为什么要用字典树,好家伙原来是用一个数组(pos)来维护字典树每个节点的对应前缀异或和数组(pre)的最右端点(可能有点绕),然后枚举右端点,在字典树上找到一条合法路径使其和 p r e [ i ] pre[i] pre[i]异或结果 ≤ k \le k k,代码注释应该说的挺清楚了

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<algorithm>
#include<cstdio>
#include<list>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))
const int mod = 1e9+7;
using namespace std;
inline int read(){
    char c=getchar();int x=0,s=1;
    while(c<'0'||c>'9'){if(c=='-')s=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*s;
}
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
#define endl '\n'
const int INF = 0x3f3f3f3f;
const int N = 3e6+10;
const int maxn = 1e3+10;
int a[N],pre[N];
int trie[N][2],cnt,pos[N];
signed main(){
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t; cin>>t;
    while(t--){
        int n,k;scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),pre[i]=pre[i-1]^a[i];//pre存前缀异或和 
        int ansl=-1,ansr=n,cnt=1;
        pos[1]=-1;
        trie[1][0]=trie[1][1]=0;
        for(int i=0;i<=n;i++){//要从i=0开始,因为pre[0]=0也要插进字典树 
            int res=-1,fa=1;
            for(int j=30;j>=0;j--){
                int w=(pre[i]>>j)&1;
                if(!((k>>j)&1)){
                //如果k>>j位上是0,那 w和w^1 都可以取,因为与 pre[i]>>j异或后 一定 >=0 
                    if(trie[fa][w^1])res=max(res,pos[trie[fa][w^1]]);
                    //因为 w 和 w^1 都能取,那就取更优解 
                    fa=trie[fa][w];
                }
                else fa=trie[fa][w^1];
                //如果k>>j位上是1,那就只能从w的异或值往下继续找,因为 w^1异或pre[j]>>j 才能等于 1 
                if(!fa)break; 
            }
            if(fa)res=max(res,pos[fa]);//找到结尾如果fa>0说明该路径合法,res取更优解 
            if(res>=0&&i-res<ansr-ansl)ansl=res,ansr=i;
            fa=1;
            for(int j=30;j>=0;j--){//插入字典树
                int w=(pre[i]>>j)&1;
                if(!trie[fa][w]){
                    trie[fa][w]=++cnt;
                    pos[cnt]=-1;
                    trie[cnt][0]=trie[cnt][1]=0;
                }
                fa=trie[fa][w];
                pos[fa]=max(pos[fa],i);
                //维护该节点对应的最右端点
            }
        }
        if(ansl!=-1)cout<<ansl+1<<" "<<ansr<<endl;
        else cout<<-1<<endl;
    }
}

Pass!(待补)

题目链接——HDU 6956


.
.
.


Maximal submatrix(待补)

题目链接——HDU 6957


.
.
.


KD-Graph

题目链接——HDU 6958


题意:
T T T 组测试数据,每组给出三个整数 n 、 m 、 k n、m、k nmk 表示无向图
G < n , m > G<n,m> G<n,m>,接下来 m m m 行,每行三个整数 u 、 v 、 w u、v、w uvw
表示顶点 u u u 和顶点 v v v 之间有一条权值为 w w w 的无向边。计算是否存在一个整数 D D D 使 n n n 个顶点分为 k k k 组 满足:
①对于任意一组,组内的顶点两两之间至少存在一条权值 ≤ w \le w w的路径
②对于任意两组,组间的顶点两两之间不存在任何一条权值 ≤ w \le w w的路径
D D D 存在输出 D D D ,否则输出 − 1 -1 1

题解:
用一个变量 n o w now now 记录当前组数,将边按权值从小到大排序,每一阶段取出同权值的所有边,将这些边的顶点用并查集两两合并,每进行一次合并 n o w − 1 now-1 now1,因为合并了一次剩下的顶点数就少了一个 ,并记录权值 w w w ,当进行到下一阶段,即边权于与上一次不一样时,判断 n o w now now的值,若等于k,则 w w w 就是答案

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<algorithm>
#include<cstdio>
#include<list>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))
const int mod = 1e9+7;
using namespace std;
inline int read(){
    char c=getchar();int x=0,s=1;
    while(c<'0'||c>'9'){if(c=='-')s=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*s;
}
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
#define endl '\n'
const int INF = 0x3f3f3f3f;
const int N = 1e6+10;
const int maxn = 1e3+10;
struct edge{
    int u,v,w;
}e[N];
int f[N];
bool cmp(edge a,edge b){return a.w<b.w;}
inline int find(int x){return f[x]==x?f[x]:f[x]=find(f[x]);}
signed main(){
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t; cin>>t;
    while(t--){
        int n,m,k; scanf("%d%d%d",&n,&m,&k);//要用scanf不然会超时
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        sort(e+1,e+1+m,cmp);
        int now=n,ans=0,flag=0;//初始时所有点都是独立的,所以now=n
        for(int i=1;i<=m;i++){
            if(e[i].w!=e[i-1].w)
                if(now==k){ printf("%d\n",ans);flag=1;break; }
                /*now==k的话,之前合并的算作一组,因为权值都<=ans
                剩下的k-1个点权值都>ans,每个点都是独立的一组
                */
            if(find(e[i].u)==find(e[i].v)) continue;
            now--; //合并一次独立的顶点就少了一个
            f[find(e[i].u)]=find(e[i].v);
            ans=e[i].w;
        }
        if(!flag)printf("%d\n",now==k?ans:-1);
    }
}

zoto

题目链接——HDU 6959


题意:
T T T 组测试数据,每组两个整数 n 、 q n、q nq,接下来一行 n n n 个整数表示数组 f x fx fx, 平面中有 n n n 个点,其中第 i i i 个的坐标为 ( i , f x [ i ] ) (i,fx[i]) (i,fx[i]),接下来 q q q 次询问,每次包含四个整数 x 1 、 y 1 、 x 2 、 y 2 x1、y1、x2、y2 x1y1x2y2,对于每次询问,输出一个整数表示在以 ( x 1 , y 1 ) (x1,y1) (x1,y1)为左下角, ( x 2 , y 2 ) (x2,y2) (x2,y2)为右上角的矩形中,有多少个 Y Y Y 坐标不同的点

题解:
由于只有询问操作,自然想到用莫队来离线处理 X X X 轴的移动,关键在于 Y Y Y 点数的维护,一开始考虑用线段树,每次 a d d add add 或者 d e l e t e delete delete 一个新点就在线段树上更新,然后区间查询,没想到线段树常数太大超时了。于是考虑对 Y Y Y 轴的区间分块处理(好像树状数组也能写,下次再来补)

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<algorithm>
#include<cstdio>
#include<list>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))
const int mod = 1e9+7;
using namespace std;
inline int read(){
    char c=getchar();int x=0,s=1;
    while(c<'0'||c>'9'){if(c=='-')s=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*s;
}
void inar(int a[],int n){for(int i=1;i<=n;i++)cin>>a[i];}
void outar(int a[],int n){for(int i=1;i<=n;i++)cout<<a[i]<<" ";cout<<endl;}
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
#define endl '\n'
const int INF = 0x3f3f3f3f;
const int N = 1e5+10;
const int maxn = 1e3+10;
int a[N],pos[N],ans[N],cnt[N],sum[N],block=313;
struct node{
    int l,r,ma,mi,id;
}query[N];
bool cmp(node a,node b){//莫队优化排序
    if(a.l/block!=b.l/block)return a.l/block<b.l/block;
    if((a.l/block)&1)return a.r>b.r;
    return a.r<b.r;
}
void add(int x){if(++cnt[x]==1)sum[x/block]++;}//找到新点就在对应的块上+1
void del(int x){if(--cnt[x]==0)sum[x/block]--;}//相反-1
int cal(int x){//分块的区间查询
    int res=0;
    for(int i=0;i<x/block;i++)res+=sum[i];
    for(int i=(x/block)*block;i<=x;i++)res+=(cnt[i]>=1);
    return res;
}
signed main(){
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t; scanf("%d",&t);//scanf不然会超时
    while(t--){
        memset(sum,0,sizeof sum); memset(cnt,0,sizeof cnt);
        int n,q;scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=q;i++){
            scanf("%d%d%d%d",&query[i].l,&query[i].mi,&query[i].r,&query[i].ma);
            query[i].id=i;
        }
        sort(query+1,query+1+q,cmp);
        int pl=query[1].l,pr=query[1].r;
        for(int i=pl;i<=pr;i++)add(a[i]);
        ans[query[1].id]=cal(query[1].ma)-cal(query[1].mi-1);
        for(int i=2;i<=q;i++){
            while(pl<query[i].l)  del(a[pl]),pl++;
            while(pr>query[i].r)  del(a[pr]),pr--;
            while(pl>query[i].l)  pl--,add(a[pl]);
            while(pr<query[i].r)  pr++,add(a[pr]);
            ans[query[i].id]=cal(query[i].ma)-cal(query[i].mi-1);
        }
        for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
    }
}

Necklace of Beads(待补)

题目链接——HDU 6960


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值