2021.06.26 考试

130=100+20+10(有进步,加油哦~)

1.游戏
【题意描述】
小喵喵喜欢玩RPG游戏。在这款游戏中,玩家有两个属性,攻击和防御,现在小喵喵的攻击和防御都是1,接下来小喵喵会依次遇到n个事件。事件有两种。
1.小喵喵经过修炼,角色升级了,此时可以选择攻击+1或者防御+1.
2.小喵喵遇到了一个敌人,可以选择战斗或者逃跑。如果战斗,胜利后得到a[i]金钱。如果逃跑,则无事发生,但是以后也不能再回来打这个怪物了。
对于一场战斗来说,如果小喵喵的攻击力大于等于atk[i],防御力大于等于def[i],那么他可以无伤打败这只怪物,从而他选择打怪,否则他发现自己会受伤,从而选择逃跑。
现在小喵喵想知道,通过巧妙地选择升级时加的属性,他最多能够从这n个事件中获得多少金钱。
【输入格式】
第1行一个整数n。
第2~n+1行每行会有一个字符’U’或’M’,分别表示升级和怪物,如果是怪物,之后有空格隔开的三个整数a[i],atk[i],def[i]。
【输出格式】
一个整数,表示最多的金钱。
【样例输入输出】
5
U
U
M 2 1 2
M 5 2 1
M 3 1 3 7
【样例解释】
小喵喵可以选择分别增加一次攻击和防御,从而可以打3号和4号怪物。总的金钱是2+5=7.

【数据范围】
对于20%的数据,n<=10
对于另外20%的数据,所有怪物的def[i]为1.
对于另外30%的数据,n<=100
对于所有的数据,n<=2000,1<=atk[i],def[i]<=n,a[i]<=109.

思路:和之前那次地图一样,动态规划,f[i] [j]表示再攻击力为i并且到了第j个关卡时,总金币数最大值。提示:每次攻击力与防御力的值增加1后,必须更新增加后的f[i] [j]的变化

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=2010;
int n,tot=2,atk[N],def[N],val[N];
ll f[N][N];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
int main(){
	//freopen("rpg.in","r",stdin);
	//freopen("rpg.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++){
		string s;
		cin>>s;
		if(s[0]=='U')atk[i]=def[i]=-1;
		else{
			val[i]=read();atk[i]=read();def[i]=read();
		}
	}
	for(int i=1;i<=n;i++){
		if(atk[i]==-1){
			++tot;
			//cout<<tot<<endl;//
			//for(int j=tot-2;j>=1;j--)f[j][i]=max(f[j][i-1],f[j+1][i-1]),cout<<f[j][i]<<" ";
			//cout<<endl;
			for(int j=1;j<tot;j++)f[j][i]=max(f[j][i-1],f[j-1][i-1]);//,cout<<f[j][i]<<" ";
			//cout<<endl<<endl;//
			continue;
		}
		//cout<<tot<<endl;//
		for(int j=tot;j>=1;j--){
			if(j>=atk[i]&&tot-j>=def[i])f[j][i]=f[j][i-1]+val[i];//,cout<<"1 j "<<j<<" ";
			else f[j][i]=f[j][i-1];//,cout<<"2 j "<<j<<" ";
			//cout<<f[j][i]<<endl;//
		}
		//cout<<endl;//
	}
	ll maxn=0;
	for(int i=1;i<tot;i++){
		//cout<<f[i][n]<<"  ";//
		maxn=max(f[i][n],maxn);
	}
	//cout<<endl<<endl;//
	cout<<maxn<<endl;
	return 0;
}
// 5 M 2 1 1 U M 1 2 1 M 5 1 2 M 4 2 2
// 7 M 2 1 1 M 6 1 2 U M 7 2 1 M 3 1 2 U M 9 3 1

2.上学
【题意描述】
小喵喵家附近有n个路口,m条道路连接着这些路口,而且通过这些道路各自需要一些时间c[i]。小喵喵在1号路口,他要去n号路口上学,但是他马上要迟到了,所以他想知道最短需要多长时间能够到达学校。其中忽略小喵喵由于出家门、到n号路口之后进入学校、从一条道路移动到另一条道路之类的时间,只计算他在这些道路上花费的时间总和。
除此之外,小喵喵还有k个时间暂停器,每个可以使某一条道路的经过时间变为0.
【输入格式】
第1行三个整数n,m,k,表示路口个数,道路的数量,时间暂停器的数量。
第2~m+1行每行三个整数u[i],v[i],c[i],表示u[i]和v[i]之间有一条可以双向通行的道路,通过所需时间为c[i]。
【输出格式】
一个整数,表示小喵喵所需的最短时间。
【样例输入输出】
5 6 1
1 2 2
1 3 4
2 4 3
3 4 1
3 5 6
4 5 2 3
【样例解释】
小喵喵选择从1->3->4->5,并且在1->3的道路上使用时间暂停器。
总耗时为0+1+2=3.
【数据范围】
对于20%的数据,n<=5,m<=10.
对于另外20%的数据,k=0.
对于另外30%的数据,k=1.
对于所有的数据,n<=1000,m<=10000,k<=10,c[i]<=109,保证存在从1号路口到n号路口的路径。注意,可能存在两条道路的起点和终点组成的集合相同,也可能存在起点和终点是相同路口的道路。

思路:分层图,共建k+1层,分别比对每一层终点的最小值

代码来自网上不知道具体是谁的老师的

#include <iostream>
#include <queue>
using namespace std;
struct Node{
    int v, w;
    Node(){}
    Node(int av, int aw): v(av), w(aw){}
    bool operator < (const Node& b) const {
        return w > b.w;
    }
}node;
vector<vector<Node> > g;
queue<Node> q;
vector<long long> dist, uptimes;
const long long INF = (long long)1 << 62;
int n, m, k, u, v, w;
bool spfa() {
    q.push(Node(1+k*n, 0)); dist[1+k*n] = 0;
    while (q.size()) {
        node = q.front(), q.pop();
        for (int i = 0, j = g[node.v].size(); i < j; ++i) {
            Node tN = g[node.v][i];
            if (dist[tN.v] > dist[node.v] + tN.w) {
                dist[tN.v] = dist[node.v] + tN.w, q.push(Node(tN.v, node.w+tN.w));
                if(++uptimes[tN.v] >= n) return false;
            }
        }
    }
    return true;
}
int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m >> k;
    g.resize(m*(k+2)); dist.resize(m*(k+2)); uptimes.resize(m*(k+2));
    fill(dist.begin(), dist.end(), INF);
    for (int i = 1; i <= m; ++i) {
        cin >> u >> v >> w;
        //使用多层图,将动态规划的各个状态以不同层列出,0边在不同层之间连接,从而避免了重边
        for (int j = 0; j <= k; ++j) {
            g[u+j*n].push_back(Node(v+j*n, w));
            g[v+j*n].push_back(Node(u+j*n, w));
            if (j) {
                g[u+j*n].push_back(Node(v+(j-1)*n, 0));
                g[v+j*n].push_back(Node(u+(j-1)*n, 0));
            }
        }
    }
    spfa();
    long long minN = INF;
    for (int i = 0; i <= k; ++i)
        minN = min(minN, dist[n+i*n]);
    cout << minN << endl;
    return 0;
}

3.数数

【题意描述】

定义一个数列的代价如下:

每次操作可以选择一个区间,和一个 2 的幂次,使得这个区间的 所有数字减去这个 2 的幂次。最少的使得这个数列全部减为 0 的操作 次数即为这个数列的代价。注意在减的时候要求二进制下这个区间的 所有数字都要是 1,即在二进制下,这个减法不能退位。

例如:5 2 2 中,不能进行[1,3]减去 2 的操作,因为(5)10=(101)2, 在第二位不是 1,所以不能减。

又如:7 5 3 数列的代价为 4,可以进行如下操作:[1,3]减 1, [1,2]减 4,[1,1]减 2,[3,3]减 2.

小喵喵有一个长度为 n 的数列 a[i]。他想知道 a[i]的所有 子序列(可以是不连续的)的代价之和。因为这个数字可能非常 大,你只需要输出 ans%998244353 的结果就可以了。

【输入格式】

第 1 行一个整数 n。 第二行 n 个用空格隔开的整数 a[i]。

【输出格式】

一个整数,表示 a[i]的所有子序列的代价之和对 998244353 取 模的结果。

【样例输入输出】

3

7 5 3

20

思路无,这一题还不会,等我什么时候会了,什么时候写,先留个坑

 posted on 2021-06-27 21:05  eleveni  阅读(81)  评论(0)    收藏  举报