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×(x∣y)
问节点1到其他节点的最短时间代价。
题解:
首先一个节点
a
a
a到另外一个节点
b
b
b,最短使用一次比特跳跃。
假如使用两次比特跳跃,代价为
k
×
(
a
∣
c
+
c
∣
b
)
k \times (a|c + c|b)
k×(a∣c+c∣b)一定
>
=
k
×
(
a
∣
b
)
>=k \times (a|b)
>=k×(a∣b).
所以最多使用一次比特跳跃。
可以先加上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+c∣x)<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+c∣x)<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;
}