2024杭电3

1012.死亡之组

题意:
n n n个队伍, n n n 4 4 4的倍数,把队伍分为若干个四人小组
死亡小组至少符号下面条件之一:
· 至少有2个队伍实力不小于L
· 实力极值差不超过D
问是否可以让1号队伍所在的组不是死亡之组。

题解:
不是死亡之组,意思就是两种条件都不满足。
最多选一个 a [ i ] > = L a[i] >=L a[i]>=L的队伍。还要保证极值差大于D
a [ 1 ] > = L a[1] >=L a[1]>=L,已经选了 a [ i ] > = L a[i] >=L a[i]>=L,再选3个最小实力的队伍。
a [ 1 ] > = L a[1] >=L a[1]>=L,选一个最大实力的队伍,再选2个最小实力的队伍。、
判断选的小组是不是死亡之组就行。

代码:

#include <bits/stdc++.h>
#define int long long
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
const int N=3e5+6;
int n,m;
int a[N];

void solve()
{
	int x;
	int L,D;
	cin>>n>>L>>D;
	rep(i,1,n)cin>>a[i];
	sort(a+2,a+n+1);
	int f=1;
	if(a[1]>=L){
		rep(i,2,4){
			if(a[i]>=L)f=0;
		}
		if(a[1]-a[2]<=D)f=0;
	}else {
		rep(i,2,3){
			if(a[i]>=L)f=0;
		}
		if(a[n]-min(a[1],a[2])<=D)f=0;
	}
	if(f){
		cout<<"Yes\n";
	}else cout<<"No\n";
}

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

1001.深度自同构

题意:
n个节点的森林,要求深度相同的节点的度也相同。问节点数为 1 1 1~ n n n时有多少种可能。

题解:
当节点为n时有一种不重复的连法。
在这里插入图片描述
所以节点数为 i i i时都可以先+1,节点数为 x x x倍数时,可以差分为若干个 x x x节点的森林。所以节点为n的森林可能性数量要加上它的可以整除的节点数的森林可能性。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+6;
const int mod=998244353;
int a[N],n;

void solve()
{
	cin>>n;
	a[1]=1;
	for(int i=2;i<=n;i++){
		a[i]++;
		for(int j=i*2;j<=n;j+=i){
			a[j]=(a[j]+a[i-1])%mod;
		}
		a[i]=(a[i-1]+a[i])%mod;
		
	}
	
	for(int i=1;i<=n;i++){
		cout<<a[i]<<' ';
	}
	cout<<'\n';
}

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

1008.比特跳跃

题意:
一个无向图,n个节点,m条边,每条边有时间代价。
一个节点到另一个节点还可以使用比特跳跃,节点 x x x与节点 y y y的时间代价为 k × ( x ∣ y ) k \times (x|y) k×(xy)
问节点1到其他节点的最短时间代价。

题解:
首先一个节点 a a a到另外一个节点 b b b,最短使用一次比特跳跃。
假如使用两次比特跳跃,代价为 k × ( a ∣ c + c ∣ b ) k \times (a|c + c|b) k×(ac+cb)一定 > = k × ( a ∣ b ) >=k \times (a|b) >=k×(ab).
所以最多使用一次比特跳跃。

可以先加上1到其他节点,代价为 k × ( 1 ∣ x ) k \times (1|x) k×(1∣x)的边。
先跑一遍迪杰斯特拉,知道现在1到各个点的最多时间。

现在考虑二进制位:
偶数节点时,会是 k × ( x + 1 ) k \times (x+1) k×(x+1).可能会有 k × ( 1 ∣ c + c ∣ x ) < k × ( 1 ∣ x ) k \times (1|c + c|x) < k \times(1|x) k×(1∣c+cx)<k×(1∣x).
奇数节点时,会是 k × x k \times x k×x.不可能会有 k × ( 1 ∣ c + c ∣ x ) < k × ( 1 ∣ x ) k \times (1|c + c|x) < k \times(1|x) k×(1∣c+cx)<k×(1∣x).
所以就考虑偶数节点时,如10100可以由1到10000或者100再到达10100节点。
如10110可以1到110,再从110到10110.

对于每个二进制数字,可以把0位变为1,把两个节点相连,再判断最短时间。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=1e6;
const int INF=1e18;
int n,m,k;
int p[MAXN];
int find(int x){
    if(x==p[x])return x;
    return p[x]=find(p[x]);
}
struct Edge{
    int to;//终点
    int length;
    Edge(int t,int l){
        to=t;
        length=l;
    }
};
struct Point{
    int number;
    int distance;
    Point(int n,int d)
    {
        number=n;
        distance=d;
    }
    bool operator<(const Point&p)const{
        return distance>p.distance;
    }
};
vector<Edge> graph[MAXN];
int dis[MAXN],mindis[MAXN];
 
void Dijkstra(int s){
    priority_queue<Point> myPriorityQueue;
    dis[s]=0;
    myPriorityQueue.push(Point(s,dis[s]));
    while(!myPriorityQueue.empty()){
        int u=myPriorityQueue.top().number;
        myPriorityQueue.pop();
        for(int i=0;i<graph[u].size();i++)
        {
            int v=graph[u][i].to;
            int d=graph[u][i].length;
            if(dis[v]>dis[u]+d){
                dis[v]=dis[u]+d;
                myPriorityQueue.push(Point(v,dis[v]));
            }
        }
    }
}
int lowbit(int x){return x & (-x);}

void solve()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        graph[i].clear();
    }
    fill(dis,dis+n+6,INF);
    while(m--)
    {
        int from,to,t;
        cin>>from>>to>>t;
        
        t=min(t,(from|to)*k);
        graph[from].push_back(Edge(to,t));
        graph[to].push_back(Edge(from,t));
        int x=find(from);
        int y=find(to);
        if(x>y)swap(x,y);
        p[y]=x;
    }
    
    for(int i=2; i<=n ;i++){
         int t=(1|i)*k;
            graph[1].push_back(Edge(i,t));
            graph[i].push_back(Edge(1,t));
        
    }
    
    Dijkstra(1);
    
    for (int i = 0;i <= n;++i) mindis[i] = dis[i];
    
    for (int i = 2;i <= n;++i){
        if (i != lowbit(i))
            for (int j = 0;(1<<j) <= n; ++j)
                if (i & (1<<j)) mindis[i] = min(mindis[i], mindis[i ^ (1<<j)]);
        if (mindis[i] + k * i < dis[i]) dis[i] = mindis[i] + k * i;
    }
    
    cout<<dis[2];
    for(int i=3; i<=n ;i++){
        cout<<' '<<dis[i];
    }
    cout<<'\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值