河南萌新联赛2024第(六)场:郑州大学

本少来也!(我是全CSDN博客用龙图第一人)

AAAAA

#include<bits/stdc++.h>
using namespace std;
long int a,b,c,d;
const long int N=1e5;
int main(){
//假设普通攻击为1,不管普通攻击是多少,比较的实质也还是sum1,sum2
    cin>>a>>b>>c>>d;
    long int sum1=N*a*b+(N-N*a);
    long int sum2=N*c*d+(N-N*c);
    if(sum1>=sum2)
        cout<<"NO";
    else cout<<"YES";
    return 0;
}

BBBBB 

这个题可能挺多的,今天尝试改了很多次,想了很多种可能,枚举倒是不太现实,先看一下我改了很久的代码,如果时间有限请略过给你们看我错的地方也同时枚举了有哪些可能 ,择其善者而从之,其不善者而改之大概的意思吧。有时做题也不要转牛角尖,虽然可能成功近在眼前,或者以后回头再看也可能豁然开朗,柳暗花明。

#include<bits/stdc++.h>
using namespace std;

bool isSame(string s, string t, int &k){
	int i = 0, j = 0;
	while (i < s.length() && j < t.length()) {
		if (s[i] != t[j]) {
			k = j;  // 记录需要删除的字符位置
			j++;    // 跳过这个字符
			break;
		}
		i++,j++;
	}
	// 在跳过一个字符的情况下,继续比较剩下的字符
	while (i < s.length() && j < t.length()) {
		if (s[i] != t[j]) {
			return false;  // 如果剩余部分不匹配,返回 false
		}
		i++,j++;
	}
	// 如果 `t` 最后一个字符没用上,那么这个字符就是被删除的字符
	if (j == t.length() - 1&&k!=j) {
		k = t.length() - 1;
	}
	return true;
}

int main(){
	string s, t;
	cin >> s >> t;
	int k = -1; // 初始化 k 为 -1,表示未找到删除位置
	if (!isSame(s, t, k)) {
		cout << 0 << endl;  // 无法匹配
	} else if((k!=t.length()-1)&&isSame(s,t,k)){
		int ans1=1;
		for(int j=k-1;j>=0;j--){
			if(t[j]==t[k]) ans1++;
		}
		cout<<ans1<<" "<<endl;
		for(int j=0;j<=k;j++){
			if(t[j]==t[k]) cout<<j<<" "<<t[j]<<endl;
		}
	}else if((k==t.length()-1)&&isSame(s,t,k)){
        int ans2=0;
		for(int j=k;j>=0;j--){
            if(t[j]==t[k]) ans2++;
        }
        cout<<ans2<<endl;
        for(int j=0;j<=k;j++){
            if(t[j]==t[k]) cout<<j<<" "<<t[k]<<endl;
        }
	}
	
	return 0;
}

下面是正确代码: 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    string s,t;
    cin>>s>>t;
    int i,j;
    for(i=0;i<s.size()&&s[i]==t[i];i++);
    for(j=s.size();j>0&&s[j-1]==t[j];j--);
    if(i>=j){
        cout<<i-j+1<<endl;
        for(int k=j;k<=i;k++) cout<<k<<" "<<t[k]<<endl;
    }else cout<<0;
    return 0;
}

代码解释: 

 CCCCC

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll n, m, v, w;

int main() {
	cin >> n >> m; 
	// 初始化二维数组dp,大小为(m+1) * 16,初始值为0
	// dp[j][k]表示胃容量为j,且幸福度模16后为k时,能吃到的最多的月饼数
	vector<vector<ll>> dp(m + 1, vector<ll>(16, 0));  
	ll i, j, k;  // 声明循环变量i, j, k
	for (i = 0; i <= m; i++) dp[i][0] = 1;  // 初始化dp数组,使得当胃容量为0时,幸福度为0,初始可吃月饼数量为1(代表0个月饼)
	
	for (i = 1; i <= n; i++) { 
		cin >> v >> w; 
		w %= 16;  //防止数据计算量过大
		// 逆序遍历胃容量,从大到小,避免重复使用同一个月饼
		for (j = m; j >= v; j--) {
			for (k = 0; k < 16; k++) {  // 遍历当前幸福度模16的值
				if (!dp[j - v][k]) continue;  // 如果前一个状态不可达,则跳过
				ll x = (w + k) % 16;  // 计算当前状态的幸福度模16的值
				// 更新dp[j][x],取之前的值和当前状态的最大值,表示能吃的最多的月饼数量
				dp[j][x] = max(dp[j][x], dp[j - v][k] + 1);
			}
		}
	}
	cout << (dp[m][0] - 1);  // 输出最终结果,减1是因为初始值为1,代表0个月饼
	return 0; 
}

1.初始化dp二维数组,把那些w%16==0情况的数初始化唯一,为什么索引要从0开始?

因为在j,k循环的时候,当j==v时,dp[j-v][k]中的,j-v==0,如果在初始化dp数组时,i不是从0开始的就会造成,索引访问越界。

2.为什么要算x,w%=16,不就是当前状态吗?

对于每对v,w都会通过i,j循环创建一个子背包,来找出当前情况下的最优解。

DDDDD

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    ll n,i;
    cin>>n;
    ll a[n];
    ll sum=0;
    for(i=0;i<n;i++){
        cin>>a[i];
    }
    ll ou=0;
    ll ji=0;
    for(i=1;i<n-1;i++){
        if(a[i]%2==0) ou=a[i]/2;//为什么不是ou++,下面有详解
        else ji++;
    }
    if(ou>=ji){
        for(i=1;i<n-1;i++){
            ll num=0;
            if(a[i]%2==0) num=a[i]/2;
            else num=(a[i]+1)/2;
            sum+=num;
        }
    }else sum=-1;
    cout<<sum;
    return 0;
}

 

EEEEE 

答案代码在这里放着了自行斟酌哦。(我龙少这辈子都没那么无语过。) 

#include<bits/stdc++.h>
#define TLE {int sum=0;for(int i=0;i<1e10;i++)sum+=i;cout<<sum;}
#define int long long
#define endl '\n'
#define rep(i, x, y) for(int i=(x), _=(y);i<=_;i++)
#define rrep(i, x, y) for(int i=(x), _=(y);i>=_;i--)
using namespace std;
const int mod = 998244353;
const double eps = 1e-6;

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

inline int read(){int c;cin>>c;return c;}
inline void readn(int a[], int n){
    for_each(a + 1, a + n + 1, [](int &x){cin>>x;});
}
inline void printn(int a[], int n){
	for_each(a + 1, a + n + 1, [](int &x){
		cout<<x<<' ';
	});
	cout<<endl;
}
template<typename T, typename... Args>
void print(const T& first, const Args&... args) {
    cout << first;
    ((cout << ' ' << args), ...);
    cout << endl;
}
template<typename T, typename... Args>
void eprint(const T& first, const Args&... args) {
	cerr<<'*';
    cerr << first;
    ((cerr << ' ' << args), ...);
    cerr << endl;
}
#define eprintn(a, n) cerr << #a << ' ';\
for(int i=1;i<=n;i++)\
	cerr<<(a)[i]<<' ';\
cerr<<endl;

const int N=1e6 + 20,M=N*2;

int n, m, k;
char out[2][10] = {"No", "Yes"};
int a[N], b[N];
int col[N];
using node = bitset<20000 + 1>;
node* cnt[N];
int top[N], fa[N];
vi edge[N];
mt19937 gen(random_device{}());
int sq;
int rnd(){
	return gen() % sq == 0;
}

signed main(){
	cin.tie(0)->sync_with_stdio(0);
	// fclose(stderr);
	// node tt;
	// tt[1] = tt[2] = 1;
	// eprint(tt.count());
	// return 0;
	
	n = read(), m = read();
	sq = sqrt(n);
	read(), read(), read();
	int c = read();
	top[1] = 1;
	fa[1] = 0;
	cnt[1] = new node;
	col[1] = c;
	(*cnt[1])[c] = 1;

	int pre = 0;
	int tmp = 0;
	while(--m){
		int op = read(), u = read() ^ pre, f = 0, c = 0;
		if(op == 0){
			f = read() ^ pre, c = read() ^ pre;
			fa[u] = f;
			col[u] = c;
			edge[f].push_back(u);
			top[u] = top[f];
			f = u;
			while(tmp++, f = top[fa[f]]){
				// assert(tmp <= 20);
				// eprint(f);
				(*cnt[f])[c] = 1;
			}
			if(rnd()){
				top[u] = u;
				cnt[u] = new node;
				(*cnt[u])[c] = 1;
			}
		}else{
			node ans;
			queue<int> que;
			que.push(u);
			// cerr << "que ";
			while(que.size()){
				int u = que.front();
				que.pop();
				// cerr << u << ' ';
				if(top[u] == u){
					ans |= *cnt[u];
				}else{
					ans[col[u]] = 1;
					for(auto &v: edge[u]){
						que.push(v);
					}
				}
			}
			// cerr << endl;
			pre = ans.count();
			print(pre);
			// eprint(ans);
		}
		// rep(i, 1, n){
		// 	if(cnt[i]){
		// 		eprint(i, *cnt[i]);
		// 	}
		// }
	}
	// eprint(clock());
}

FFFFF 

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
int main(){
    ll n;
    cin>>n;
    ll i,j;
    vector<ll> a(n);
    for(i=0;i<n;i++) cin>>a[i];
    ll sum=0,max=0;
    for(i=n-1;i>0;i--){
        if(a[i]>=max){
            max=a[i];
            sum++;
        }
    }
    cout<<sum-1;
    return 0;
}

这是一个易错题,下面看两个代码:

左边的代码是正确的,但是右边的是错的,没想到吧,我龙龙公主也是无语了。

说直接点就是,这些灯光是一段一段的递增的,人眼再看灯光的时候,如果先看的是强光a,然后遇到稍微暗一点或者稍微强一点的光b,就容易误判了,不知道到底b光是比a光强还是弱。逆向遍历的时候,你不用管光到底多弱,找到目前最强的一束光就行了。

GGGGG

#include<bits/stdc++.h>
using namespace std;
using ll =long long;
const ll N=2e5+10;
ll d[N],t[N];
int main(){
	ll n,m,q;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>d[i];
	for(int i=1;i<=m;i++)
		cin>>t[i];
	cin>>q;
	while(q--){
		ll l,r;
		cin>>l>>r;
		ll k=lower_bound(t+1,t+m+1,l-d[r])-t;//一第一个作为起点,其他的点依次递增变化了来求解问题
		if(k>=m+1)
			cout<<"TNT"<<'\n';
		else
			cout<<t[k]+d[r]-l<<'\n';
	}
	return 0;
}

1.二分查找:ll k = lower_bound(t + 1, t + m + 1, l - d[r]) - t; 使用lower_bound进行二分查找。lower_bound的作用是在数组t中找到第一个大于等于l - d[r]的元素位置,并返回它的指针。通过减去t,得到这个元素在数组中的位置索引k。

2.判断是否超出范围:if (k >= m + 1) 如果索引k等于m + 1,说明在数组t中没有找到满足条件的元素,输出"TNT"表示无解。 

HHHHH

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N=1e3+10;

map<string,int> mp={
	{"A",1},{"2",2},{"3",3},{"4",4},{"5",5},{"6",6},{"7",7},
	{"8",8},{"9",9},{"10",10},{"J",11},{"Q",12},{"K",13},
};

int f(vector<double> a)
{
	//结束条件 
	//递归处理每个数,如果只剩1个数,比较一下与24的关系,但是除法有误差 
	if(a.size()==1) return abs(a[0]-24)<1e-6;
	
	for(int i=0;i<a.size();i++){//枚举第一个数字 
		for(int j=0;j<a.size();j++){
			if(i!=j){//当两者不为同一个数时,可进行操作
				vector<double> b;
				for(int k=0;k<a.size();k++){
					//将剩余数字存入b中 
					if(k!=i&&k!=j){
						b.push_back(a[k]); 
					}
				}
				//枚举四种操作 
				for(int op=0;op<4;op++){
					//a+b==b+a和a*b==b*a,所以出现这两种情况,可以剪枝 
					if(op<2&&i>j) continue;
					switch(op){
						//加法,将枚举的两个数字相加并加入b中 
						case 0:b.push_back(a[i]+a[j]); break;
						//乘法 
						case 1:b.push_back(a[i]*a[j]); break;
						//减法 
						case 2:b.push_back(a[i]-a[j]); break;
						//除法 
						case 3:b.push_back(a[i]/a[j]); break;
					} 
					//递归处理剩下的数字,直到只剩一个数字 
					if(f(b)) return 1;
					b.pop_back(); 
				} 
			}
		}
	}
    return 0;
}

void solve()
{
	vector<double> a(4);
	for(int i=0;i<4;i++){
		string s;cin>>s;
		a[i]=mp[s];
	}
	sort(a.begin(),a.end());
	
	//全排列处理每种情况 
	do{
		if(f(a)){
			cout<<"YES"<<endl;
			return;
		}
	}while(next_permutation(a.begin(),a.end()));
	cout<<"NO"<<endl;
}

signed main()
{
	int t;cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

IIIII 

这题也比较容易写超时。跟着龙龙看看这个题叭,我发现了一个规律,根据自己的思路写了个代码但是没有成功,先放在这里,后来看的时候如果再试一遍修改成功了就改到博文里面。

我的代码:(错误版)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    int n, m;
    cin >> n >> m;
    string s;
    cin >> s;
    string s1=s;
    
    vector<ll> index(n);
    ll i;
    ll j=0;
    for(i=m-1;i>0;i-=2)index[j++]=i;
    
    index[j++]=0;
    
    if(m%2==0){
        for(i=2;i<=m-2;i+=2)index[j++]=i;
    }else{
        for(i=1;i<=m-2;i+=2)index[j++]=i;
    }
    for(i=m;i<n;i++)index[j++]=i;
    
    vector<ll> flag(n,0);
    for(i=0;i<m;i++){
        for(j=0;j<=i;j++){
            if((i+1)%2!=0){
                if(j!=(i/2))
                    flag[j]++;
            }else flag[j]++;
        }
    }
    
    for(i=0;i<m;i++){
        if(flag[i]%2!=0){
            if(flag[i]=='P') s1[i]='B';
            else s1[i]='P';
        }else continue;
    }
    ll cnt=0;
    for(i=index[cnt++];i<m;i++)cout<<(s1[i]=='B'?"0 ":"1 ");
    for(i=m;i<n;i++)cout<<(s1[i]=='B'?"0 ":"1 ");
    return 0;
}

 

正确代码: 

#include<bits/stdc++.h>
using namespace std;
string s,s1;
int main(){
	int n,m;
	cin>>n>>m;
	cin>>s;
	s1=s;
	int j=0,k=m-1;
	for(int i=m-1;i>=0;i--){
		if((m-i)%2==1){
			if(s[i]=='P')s1[j++]='B';
			else s1[j++]='P';
		}else{
			if(s[i]=='P')s1[k--]='P';
			else s1[k--]='B';
		}
	}  
	for(int i=0;i<n;i++)cout<<(s1[i]=='B'?"0 ":"1 ");
	return 0;
}

 

 JJJJJ

 

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2010;
int dp[N][N],n;
typedef pair<int,int> PII;
PII a[N];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        a[i]={x,i};
    }
    sort(a+1,a+n+1);
    for(int len=1;len<=n;len++){
        auto [w,id]=a[len];
        for(int l=1,r=l+len-1;r<=n;l++,r++){
            dp[l][r]=max(dp[l+1][r]+abs(l-id)*w,dp[l][r-1]+abs(r-id)*w);
        }
    }
    cout<<dp[1][n]<<endl;
    return  0;
}
  • PII:定义了一个类型为 pair<int, int> 的别名,方便存储选手的能力值和初始位置。
  • a[N]:用来存储每个选手的能力值和位置,a[i].first 表示第 i 个人的能力值,a[i].second 表示第 i 个人的原始编号。
  • auto [w, id] = a[len]:这里用 C++17 的结构化绑定特性,从选手数组 a 中取出当前能力值 w 以及对应的原始编号 id
  • 内层循环依次考虑左边界 l 和右边界 r,它们表示当前区间的两端。
  • dp[l][r] 表示区间 [l, r] 的最大增幅值:
    • 如果选择左端 l,则从 l+1r 的问题已经解决,增幅为 dp[l+1][r],加上当前选手放在左端的增幅 abs(l - id) * w
    • 如果选择右端 r,则从 lr-1 的问题已经解决,增幅为 dp[l][r-1],加上当前选手放在右端的增幅 abs(r - id) * w
    • 两者取最大值,更新 dp[l][r]
  • 问题划分:我们将问题划分为一个一个子问题,也就是考虑从左端或右端依次放置选手的过程,并通过 dp[l][r] 来保存子问题的解。
  • 状态转移:我们可以从已知的 dp[l+1][r]dp[l][r-1] 来推导出 dp[l][r] 的值。
  • 边界条件:当 l == r 时,即只剩下一个选手,临场发挥值仅取决于该选手所在的编号和位置差。

 KKKKK

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
vector<int> g[N], g1[N];
int degree[N], vis[N];

void solve() {
    int n, m;
    cin >> n >> m;
    vector<pair<int, int>> ed;
    
    // 读取输入并建图
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
        degree[u]++;
        degree[v]++;
        ed.push_back({u, v});
    }

    // 构建优化后的有向图 g1
    for (auto [u, v] : ed) {
        if (degree[u] > degree[v] || (degree[u] == degree[v] && u > v)) {
            swap(u, v);
        }
        g1[u].push_back(v);
    }

    long long res = 0, p = 0;

    // 三元环计数
    for (int i = 1; i <= n; i++) {
        for (auto j : g1[i]) vis[j] = i;
        for (auto j : g1[i]) {
            for (auto w : g1[j]) {
                if (vis[w] == i) res++;
            }
        }
    }
    p = res;

    // 三芒星计数
    for (int i = 1; i <= n; i++) {
        if (degree[i] >= 3) {
            res += degree[i] * (degree[i] - 1) * (degree[i] - 2) / 6;
        }
    }

    // 闪电链计数
    for (auto [u, v] : ed) {
        int a = g[u].size() - 1;
        int b = g[v].size() - 1;
        res += a * b;
    }

    // 减去重复的三元环计数
    res -= 3 * p;

    cout << res <<endl;
}

int main() {
    ios::sync_with_stdio(0),cin.tie(0);
    solve();
    return 0;
}
  • g[N]:用于存储原始图的邻接表。
  • g1[N]:用于存储经过一定优化处理后的图(降低复杂度的处理)。
  • degree[N]:记录每个节点的度数(有多少个相邻节点)。
  • vis[N]:用于记录访问状态,在后续的三元环计数中会用到。
  • 这里构建 g1 的目的在于优化三元环的计数:将度数较小的节点连接到度数较大的节点,减少冗余的三元环查找次数。
  • 三元环的这段计算中,双重循环通过邻接表查找两个节点是否有共同的邻居,如果有则说明形成了三元环。
  • res 记录三元环的数量,p 保存三元环的总数用于后续调整。
  • 闪电链指的是两条边共享一个节点的结构。
  • 由于三芒星和闪电链计数过程中可能包含了三元环,因此需要减去三元环的贡献,减去 3 * p。

 

LLLLL 

 

这段代码实现了著名的约瑟夫环问题(Josephus Problem),即一个循环链表中,按照某个固定的步长(这里是 k),顺序删除节点,直到只剩下最后一个节点。具体的过程如下:

举个例子:

假设输入 n = 5k = 2,表示有 5 个节点,并且每次跳 2 个节点删除一个节点,程序的操作如下:

  1. 构造包含 1, 2, 3, 4, 5 这 5 个节点的循环链表。
  2. 按照每次跳 2 步的规则,第一次删除节点 2,链表变为 1, 3, 4, 5
  3. 再跳 2 步,删除节点 4,链表变为 1, 3, 5
  4. 再跳 2 步,删除节点 1,链表变为 3, 5
  5. 再跳 2 步,删除节点 5,链表剩下节点 3。 

最终输出的删除顺序是 2 4 1 5

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n,k;
    cin>>n>>k;
    deque<int> a;
    for(int i=1;i<=n;i++) a.push_back(i);
    int t=0;
    while(a.size()!=1)
    {
        t=(t+k-1)%a.size();
        cout<<a[t]<<' ';
        a.erase(a.begin()+t);
    }
    return 0;
}

 

Good Bye!Bye bye! 

 

 

 

 

 

 

 

 

 


 

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值