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;
}
posted @ 2025-06-15 12:25  usedchang  阅读(22)  评论(0)    收藏  举报