2024杭电多校第三场

目录

1001-深度自同构

1003-游走

1007-单峰数列

1008-比特跳跃

1011-抓拍

1012-死亡之组


1001-深度自同构

每个数的答案其实与它的各个因数有关,正向递推一下

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
const int mod=998244353;
int a[N],d[N],f[N];
void solve(){
	int n;
	cin>>n;
	cout<<1<<' ';
	a[1]=1;
	for(int i=2;i<=n;i++){
		f[i]+=1;
	}
	for(int i=2;i<=n;i++){
		d[i]=a[i-1];
		a[i]=(d[i]+f[i])%mod;
		for(int j=i*2;j<=n;j+=i)
			f[j]=(f[j]+d[i])%mod;
		cout<<a[i]<<' ';
	}
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
//    cin >> t;
	while (t--) solve();

	return 0;
}

1003-游走

主要是几个点要注意

1:每次插入的数前后路程距离不能大于时间差距,奇偶性要相同,

2:如果开头是一段连续的1,那最小和最大需要特殊考虑

3:最小的答案一定是不减的

#include "bits/stdc++.h"

using namespace std;
#define int long long


bool check(int q1, int p1, int q2, int p2, int &mint, int &maxt) {
    int dp = abs((p1 - p2));
    if (p2 != 1) {
        maxt = min(maxt, q2 - dp);
    }
    if (p1 == 1 && (q2 - q1) % 2 != dp % 2 && q2 - q1 >= dp) {
        mint = max(mint, q1 + 1);
        return true;
    }
    return dp % 2 == (q2 - q1) % 2 && dp <= q2 - q1;

}

void solve() {
    int n, m;
    cin >> n >> m;
    map<int, int> f;
    f[0] = 1;
    bool bad = false;
    int mint = 0;
    int maxt = numeric_limits<int>::max();
    while (m--) {
        int op;
        cin >> op;
        if (op == 0) {
            int p, q;
            cin >> p >> q;
            if (bad) {
                continue;
            }
            if (f.count(q)) {
                if (f[q] != p) {
                    bad = true;
                }
                continue;
            }
            auto it = f.emplace(q, p).first;
            auto itl = prev(it);
            auto [q1, p1] = *itl;
            auto [q2, p2] = *it;
            if (!check(q1, p1, q2, p2, mint, maxt)) {
                bad = true;
                continue;
            }
            auto itr = next(it);
            auto [q3, p3] = *itr;
            if (itr != f.end() && !check(q2, p2, q3, p3, mint, maxt)) {
                bad = true;
            }
            if (mint > maxt) {
                bad = true;
            }
        } else if (op == 1) {
            if (bad) {
                cout << "bad" << '\n';
            } else {
                cout << mint << '\n';
            }
        } else {
            if (bad) {
                cout << "bad" << '\n';
            } else if (maxt == numeric_limits<int>::max()) {
                cout << "inf" << '\n';
            } else {
                cout << maxt << '\n';
            }
        }
    }
}


signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--)solve();

    return 0;
}

1007-单峰数列

线段树维护

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5+50;
int treez[maxn<<2],treef[maxn<<2],treegd[maxn<<2];
int a[maxn],c[maxn];
void pushup(int p) {                 //更新节点的值
	treez[p]=treez[p<<1]+treez[p<<1|1];
	treef[p]=treef[p<<1]+treef[p<<1|1];
	treegd[p]=treegd[p<<1]+treegd[p<<1|1];
}
void build(int p,int l,int r) {     //建树 树节点为p (左儿子p*2 右儿子p*2+1) l为区间左端点 r为右端点
	if(l==r) {
		if(c[l]>0) treez[p]++;
		else if(c[l]<0) treef[p]++;
		return;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	pushup(p);
	if(c[mid]>0&&c[mid+1]<0) treegd[p]++;
	else if(c[mid]<0&&c[mid+1]>0) treegd[p]+=10;
}

void update(int p,int l,int r,int x,int y,int w) { //更新区间 (x,y) 的值 改变量为w
	if(l==r) {
		if(c[l]>0) treez[p]--;
		else if(c[l]<0) treef[p]--;
		c[l]=c[l]+w;
		if(c[l]>0) treez[p]++;
		else if(c[l]<0) treef[p]++;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)update(p<<1,l,mid,x,y,w);
	if(mid<y)update(p<<1|1,mid+1,r,x,y,w);
	pushup(p);
	if(c[mid]>0&&c[mid+1]<0) treegd[p]++;
	else if(c[mid]<0&&c[mid+1]>0) treegd[p]+=10;
}

int queryz(int p,int l,int r,int x,int y) {
	int ans=0,mid=(l+r)>>1;
	if(x<=l&&r<=y) {
		return treez[p];
	}
	if(x<=mid) ans+=queryz(p<<1,l,mid,x,y);
	if(mid<y) ans+=queryz(p<<1|1,mid+1,r,x,y);
	return ans;
}
int queryf(int p,int l,int r,int x,int y) {
	int ans=0,mid=(l+r)>>1;
	if(x<=l&&r<=y) {
		return treef[p];
	}
	if(x<=mid) ans+=queryf(p<<1,l,mid,x,y);
	if(mid<y) ans+=queryf(p<<1|1,mid+1,r,x,y);
	return ans;
}
int querygd(int p,int l,int r,int x,int y) {
	int ans=0,mid=(l+r)>>1;
	if(x<=l&&r<=y) {
		return treegd[p];
	}
	if(x<=mid) ans+=querygd(p<<1,l,mid,x,y);
	if(mid<y) ans+=querygd(p<<1|1,mid+1,r,x,y);
	if(x<=mid&&mid<y) {
		if(c[mid]>0&&c[mid+1]<0) ans++;
		else if(c[mid]<0&&c[mid+1]>0) ans+=10;
	}
	return ans;
}
void solve() {
	int n,q,x,y,w,numz,numf,numgd;
	int op;
	cin>>n;
	for(int i=1; i<=n; i++)
		cin>>a[i];
	for(int i=0; i<=n; i++)
		c[i]=a[i+1]-a[i];
//	for(int i=0;i<=n;i++) cout<<i<<' '<<c[i]<<'\n';
	build(1,1,n);
	cin>>q;
	for(int i=1; i<=q; i++) {
		cin>>op;
		if(op==1) {
			cin>>x>>y>>w;
			if(x>0) update(1,1,n,x-1,x-1,w);
			update(1,1,n,y,y,-1*w);
		} else if(op==2) {
			cin>>x>>y;
			if(x==y) {
				cout<<1<<'\n';
				continue;
			}
			numz=queryz(1,1,n,x,y-1);
			numf=queryf(1,1,n,x,y-1);
			if(!numz&&!numf) cout<<1<<'\n';
			else cout<<0<<'\n';
		} else if(op==3) {
			cin>>x>>y;
			if(x==y) {
				cout<<1<<'\n';
				continue;
			}
			numz=queryz(1,1,n,x,y-1);
			if(numz==y-x) cout<<1<<'\n';
			else cout<<0<<'\n';
		} else if(op==4) {
			cin>>x>>y;
			if(x==y) {
				cout<<1<<'\n';
				continue;
			}
			numf=queryf(1,1,n,x,y-1);
			if(numf==y-x) cout<<1<<'\n';
			else cout<<0<<'\n';
		} else {
			cin>>x>>y;
			if(x==y) {
				cout<<0<<'\n';
				continue;
			}
			numgd=querygd(1,1,n,x,y-1);
			numz=queryz(1,1,n,x,y-1);
			numf=queryf(1,1,n,x,y-1);
			if(numgd==1&&numz+numf==y-x) cout<<1<<'\n';
			else cout<<0<<'\n';
		}
	}
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
//    cin >> t;
	while (t--) solve();

	return 0;
}

1008-比特跳跃

首先,如果不考虑已经有的道路,只进行跳跃的话,跳两次一定比跳一次更优。所以首先可以从1出发,连到每个点,先连一条边,权值为比特跳跃的花费。

其次考虑二进制位,如1100可以由1000和100这样的只有一位01不同的转移过来,因为上一个前提,最多就连续跳一次,所以可以对于每个数,遍历每个二进制位,把一个0的位置变成1,把前后两个数进行连边。复杂度是18*n

最后跑一边迪杰斯特拉即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
const int mod=998244353;
int n,m,k;
vector<pair<int,int>>to[N];
int dis[N];
int vis[N];
void dij(){

    dis[1] = 0 ;

    priority_queue<pair<int,int>>q;
    q.push({0,1});

    while(!q.empty()){

        int  u =q.top().second;

        q.pop();
        vis[u] = 1;

        for(int i=0;i<to[u].size();i++){
            int v =to[u][i].first;
            int w =to[u][i].second;
            if(vis[v])continue;

            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                q.push({-dis[v],v});
            }
        }

    }

}

void bfs(){

    queue<int>q;
    for(int i=0;i<=18;i++){
        int k=1<<i;
        if(k<=n){
            q.push(k);
            vis[k]=1;
        }
    }
    while(!q.empty()){
        int x=q.front();

        q.pop();
        for(int i=0;i<=17;i++){
            if(((x>>i)&1)==0){
                int y=x|(1<<i);
                if(y>n)continue;
                to[x].push_back({y,(x|y)*k});
                to[y].push_back({x,(x|y)*k});
                dis[y]=min(dis[y],dis[x]+(x|y)*k);
                if(vis[y]==1)continue;
                q.push(y);
                vis[y]=1;
            }
        }
    }
}
void solve(){
    cin >>n>>m>>k;
    for(int i=1;i<=n;i++){
        dis[i] = 1e15;
        to[i].clear();
    }
    for(int i=2;i<=n;i++){
        to[1].push_back({i,k*(1|i)});
    }
    for(int i=1,u,v,w;i<=m;i++){
        cin>>u>>v>>w;
        w=min(w,(u|v)*k);
        to[u].push_back({v,w});
        to[v].push_back({u,w});
    }
    for(int i=1;i<=n;i++)vis[i]=0;
    bfs();
    for(int i=1;i<=n;i++)vis[i]=0;
    dij();
    for(int i=2;i<=n;i++)cout<<dis[i]<<" ";
    cout<<'\n';
    
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
/*
 *
 * 1
6 4 3
1 3 2
1 5 20
2 4 1
4 6 10
 *
 * */

1011-抓拍

处理出边界,进行三分

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
const int mod=998244353;
int lx[4],rx[4],ly[4],ry[4];
int jxx1,jxx2,jxy1,jxy2;
int n;
int cf1d0[4],c0dz1[4];
int tim[10],js=0;
string s;
struct node{
	int x,y;
};
vector<node>v[4];
double check(double t){
	double maxx=-1*1e12,minx=1e12,maxy=-1*1e12,miny=1e12;
	if(!v[0].empty()){
		maxx=max((double)rx[0],maxx);
		minx=min((double)lx[0],minx);
		maxy=max((double)ry[0]+t,maxy);
		miny=min((double)ly[0]+t,miny);
	}
	if(!v[1].empty()){
		maxx=max((double)rx[1],maxx);
		minx=min((double)lx[1],minx);
		maxy=max((double)ry[1]-t,maxy);
		miny=min((double)ly[1]-t,miny);
	}
	if(!v[2].empty()){
		maxx=max((double)rx[2]+t,maxx);
		minx=min((double)lx[2]+t,minx);
		maxy=max((double)ry[2],maxy);
		miny=min((double)ly[2],miny);
	}
	if(!v[3].empty()){
		maxx=max((double)rx[3]-t,maxx);
		minx=min((double)lx[3]-t,minx);
		maxy=max((double)ry[3],maxy);
		miny=min((double)ly[3],miny);
	}
	return (maxx-minx)*2+(maxy-miny)*2;
}
void solve(){
	node t;
	for(int i=0;i<4;i++){
		lx[i]=1e12;
		rx[i]=-1*1e12;
		ly[i]=1e12;
		ry[i]=-1*1e12;
	}
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>t.x>>t.y>>s;
		if(s[0]=='N') v[0].push_back(t);
		if(s[0]=='S') v[1].push_back(t);
		if(s[0]=='E') v[2].push_back(t);
		if(s[0]=='W') v[3].push_back(t);
	}
	for(int i=0;i<4;i++){
		for(int j=0;j<v[i].size();j++){
			t=v[i][j];
			lx[i]=min(t.x,lx[i]);
			rx[i]=max(t.x,rx[i]);
			ly[i]=min(t.y,ly[i]);
			ry[i]=max(t.y,ry[i]);
		}
	}
	double l=0,r=2e9;
	double mid1,mid2;
	while(fabs(r-l)>=1e-6){
		mid1=l+(r-l)/3.0;
		mid2=l+(r-l)*2/3.0;
		if(check(mid1)<check(mid2)) r=mid2;
		else l=mid1;
	}
	int aa=(int)l;
	int ans;
	ans=min(min(check(max(0ll,aa-1)),check(aa)),check(aa+1));
	cout<<ans<<'\n';
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
//    cin >> t;
	while (t--) solve();

	return 0;
}

1012-死亡之组

考虑小于的个数,以及自身是否小于l即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int N = 2e5 + 100;
const int mod=998244353;




int a[N];
void solve(){
    int n,l,d;
    cin>>n>>l>>d;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int k=a[1];
    sort(a+1,a+n+1);
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(a[i]<l)cnt++;
    }
    if(cnt>=3){
        if(k>=l){
            if(k-a[1]>d){
                cout<<"Yes"<<'\n';
            }else{
                cout<<"No"<<'\n';
            }
        }else{
            if(a[n]-a[1]>d){
                cout<<"Yes"<<'\n';
            }else{
                cout<<"No"<<'\n';
            }
        }
    }else{
        cout<<"No"<<'\n';
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    cin>>T;
    while (T--)solve();

    return 0;
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心刍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值