At410 ABCDE
A.G1
题意简述
求序列中大于等于 k 的数的个数
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n;cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
int k;cin>>k;
int ans=0;
for(int i=1;i<=n;i++) ans+=(a[i]>=k);
cout<<ans<<endl;
return 0;
}
B.Reverse Proxy
题意简述
给一个操作序列,要求把 球放进盒子里,如果 \(q_i\) 是 0,把球放进球最少的盒子(如果有多个,取最小序号的)里,如果不是 0 ,把球放进 第 \(q_i\) 个盒子里,求每个球是在哪个盒子里的?
解题思路
数据很小,直接暴力模拟即可
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n,q;cin>>n>>q;
vector<int>a(n+1);
for(int i=1;i<=q;i++){
int x;cin>>x;
if(!x) x=min_element(a.begin()+1,a.end())-a.begin();
++a[x];
cout<<x<<" \n"[i==q];
}
return 0;
}
C.Rotatable Array
题意简述
给定一个长为 \(N\) 的序列 \(A\) , 一开始 \(A_i = i\). 执行以下 \(Q\) 个操作
操作 \(1\): 使得 \(A_p\) 等于 \(x\).
操作 \(2\): 输出 \(A_p\).
操作 \(3\): 使得数组循环左移 \(k\) 位
正式的说, 使得 \(A\) 成为 \((A_2,A_3,\dots,A_N,A_1)\) 重复 \(k\) 次.
解题思路
很显然操作 \(1\) 和操作 \(2\) 我们可以直接 \(O(1)\) 的完成修改和输出,难点在于操作 \(3\) 的完成,由于循环移位,把整个数组看成首位相接的环,那么每次就是在环上移动,优先考虑模运算,每次移位就是对当前所有数加上一个循环左移值,我们要维护的就是这个值。
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n,q;cin>>n>>q;
vector<int>a(n+1);
for(int i=1;i<=n;i++) a[i]=i;
int k=0,p,x;
for(int i=1;i<=q;i++){
int op;cin>>op;
if(op==1){
cin>>p>>x;
a[(p+k+n-1)%n+1]=x;
}
else if(op==2){
cin>>p;
cout<<a[(p+k+n-1)%n+1]<<endl;
}
else if(op==3){
cin>>p;
k=(k+p)%n;
}
}
return 0;
}
D.XOR Shortest Walk
题意简述
给定一个 \(N\) 个顶点和 \(M\) 条边的有向图,其中顶点从 \(1\) 到 \(N\) 编号,边从 \(1\) 到 \(M\) 编号。边i是从顶点 \(A_i\) 到顶点 \(B_i\) 的有向边,权重为 \(W_i\) 。
找到从顶点 \(1\) 到顶点 \(N\) 的路径中包含的边的权重的逐位XOR的最小值。
解题思路
异或和的最短路径肯定是允许边点重复走,甚至可能有环的,因此不能采用一般简单路径的遍历方式,然后考虑如何不重不漏的遍历每一个合法的状态,考虑到每一个点可能的状态数非常的小,那么我们可以用一个 \(vis_{u,j}\)来记录,表示从原点走到第 \(u\) 个点,最小异或和是 \(j\) 的路径是否存在,然后从原点开始跑 \(bfs\) 就好了
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
struct node{
int u;ll w;
};
const int N=1005;
bool vis[N][1025];
vector<node>G[N];
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n,m;cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;ll w;cin>>x>>y>>w;
G[x].push_back({y,w});
}
queue<pair<int,ll> >Q;//点,从起点到这个点的异或和
Q.push({1,0});
vis[1][0]=1;
while(!Q.empty()){
int u=Q.front().first;
int val=Q.front().second;
Q.pop();
for(auto &[v,w]:G[u]){
if(!vis[v][val^w]){
vis[v][val^w]=1;
Q.push({v,val^w});
}
}
}
int ans=-1;
for(int i=0;i<=1024;i++){
if(vis[n][i]) {ans=i;break;}
}
cout<<ans<<endl;
return 0;
}
E.Battles in a Row
题意简述
有一个游戏,按照顺序挑战 \(N\) 个怪物。最初的生命值 是 \(H\),魔法值是 \(M\)。
对于第 \(i\) 个挑战的怪物,他可以选择以下之一行动:
不使用魔法战斗:只能在生命值至少为 \(A_i\) 时选择,生命值减少 \(A_i\),怪物被击败。
使用魔法战斗:只能在魔法值至少为 \(B_i\) 时选择,魔法值减少 \(B_i\),怪物被击败。
当所有 \(N\) 个怪物都被击败或无法采取任何行动时,游戏结束。在游戏结束前,他能击败的最大数量的怪物是多少?
解题思路1
他是按顺序挑战,并且 当前怪兽无论如何无法战胜就不会挑战下个怪兽,那么考虑 \(dp\) 规划 ,定义状态击败前 \(i\)只怪兽消耗 \(j\) 点体力下的最小魔力值,初始化消耗的魔力为极大值,而击败 \(0\) 只怪兽使用 \(0\) 点体力消耗的魔力值为 \(0\), \(dp_{i,j}=dp_{i-1,j-a_i},dp_{i,j-1}+b_i\),最后从高位到低位检查的魔力值是否小于 \(w\) 即可
AC code1
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const int INF=0x3f3f3f3f;
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n,h,w;cin>>n>>h>>w;
vector<int>a(n+1),b(n+1);
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
vector<vector<int> >dp(n+1,vector<int>(h+1,INF));//解决前 i只怪兽消耗 j点体力值下消耗的最小魔力值
dp[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=h;j++){
if(j>=a[i]) dp[i][j]=min(dp[i-1][j-a[i]],dp[i][j]);
dp[i][j]=min(dp[i-1][j]+b[i],dp[i][j]);
}
}
int ans=0;
for(int i=n;i>=1;i--){
for(int j=1;j<=h;j++){
if(dp[i][j]<=w) {
ans=i;
break;
}
}
if(ans) break;
}
cout<<ans<<endl;
return 0;
}
解题思路2
定义 \(dp_{i,j,k}\) 为遍历到第 \(i\)位消耗 \(j\) 的体力和 \(k\) 的魔力是否可能击败当前所有的怪兽,可能保持 1 ,不可能保持 0,考虑优化空间和时间 空间上第一维度可以直接省去,时间复杂度上考虑用 $ bitset $优化转移操作,总复杂度 \(O(n^3/w)\)
AC code2
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n,h,w;
cin>>n>>h>>w;
vector< bitset<3001> >dp(h+1);
vector<int>a(n+1),b(n+1);
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
dp[h][w]=1;
for(int i=1;i<=n;i++){
vector< bitset<3001> >New(h+1);
bool f=0;
for(int j=0;j<=h;j++) {
if(dp[j].none()) continue;//如果击败前x只怪兽消耗i点体力的情况下不可能有消耗j点魔力,那么跳过当前魔力值
if(j>=a[i]) New[j-a[i]]|=dp[j];//消耗体力
New[j]|=(dp[j]>>b[i]);//消耗魔力
}
for(int j=0;j<=h;j++) f|=New[j].any();
if(!f) return cout<<i-1<<endl,0;
dp=New;
}
cout<<n<<endl;
return 0;
}

浙公网安备 33010602011771号