Septemper daily training (一)

写在前面:

这是自己选的一场codeforce 1400-1600 的题。

写写训练日常吧,杜绝自己摸鱼 -- 训练时间 8.9下午

A.Diverse game

       解析:

       题目保证了矩阵a中的所有数字都是不同的,直接将所有元素往后挪一位,将最后一位挪到第一位即可。

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N=1e5;


inline void solve() {
	int n,m; cin >> n >> m;
	vector<int>a(n*m);
	int cnt=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin >> a[cnt++];
		}
	}
	if(n*m==1) {cout << -1 <<'\n';return;}
	int jx=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i==n && j==m) {cout << a[0] <<'\n';return;}
			cout << a[jx++] << ' ';
		}
		cout << '\n';
	}
}

int main() {
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
	std::cin >> T;
	while (T--) solve();
	return 0;
}

B. Fun Game

解析:

        考虑到,01序列中任意一个字符可以被第一个字符单点修改,那么只要 s 的第一个是‘1’,s就一定可以转换为t,进一步的我们可以发现,后面的数字是可以被前面的数字影响的,而前面的数字最多只能被自己影响,又因为1可以将0变1,1变0,所以我们只需要找到俩个序列的第一个1,判断一下,s的第一个1是不是出现得比 t 早就可以了。特判一下,t 中没有1的情况即可。

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N=1e5;


inline void solve() {
	int n; string s,S; cin >> n >> s >> S;
	if(s[0]=='1') cout << "YES" << '\n';
	else {
		int c=-1,d=-1;
		for(int i=0;i<n;i++){
			if(s[i]=='1' && c==-1) c=i;
			if(S[i]=='1' && d==-1) d=i;
			if(c!=-1 && d!=-1) break; 
		}
		if(d==-1) cout <<"YES"<<'\n';
		else if(c<=d && c!=-1 && d!=-1) cout << "YES"<<'\n';
		else
		cout << "NO" << '\n';
	}	
}

int main() {
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
	std::cin >> T;
	while (T--) solve();
	return 0;
}

C. Hungry Games

解析:

        正难则反,考虑到所有子区间为 n*(n+1)/2 ,计算出g值为0的区间数目,俩者相减就是答案

双指针扫一遍就好了,注意俩个相邻的区间可以合并。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;

ll a[N];
inline void solve() {
	//有多少个存在子区间大小刚好超过x的连续子区间
	ll n, x;
	cin >> n >> x;
	for (int i = 1; i <= n; i++) cin >> a[i];
	ll sum = 0, ans = 0, cnt = 1; // cnt 为左端点
	map<int, int>mp; // 存以端点 i 为右端点的区间和刚好大于x的数目,此时对于另一个紧挨着的以端点 i + 1
	// 为左端点的同样一个区间,此时对于答案的贡献就是 mp[i-1] + 1
	for (int i = 1; i <= n; i++) {
		sum += a[i];
		if (sum > x) {
			while (sum > x) sum -= a[cnt], ans += mp[cnt - 1] + 1, mp[i] += mp[cnt - 1] + 1, cnt++;
		}
	}
	cout << n*(n + 1) / 2 - ans << '\n';


}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	std::cin >> T;
	while (T--) solve();
	return 0;
}

D. Two Movies

解析:

简单模拟题,注意细节贪心求即可

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;

int A[N], B[N];
inline void solve() {
	int n;
	cin >> n;
	int x = 0, y = 0;
	int a = 0, b = 0;
	for (int i = 1; i <= n; i++) cin >> A[i];
	for (int i = 1; i <= n; i++) cin >> B[i];
	for (int i = 1; i <= n; i++) {
		int u, v;
		u = A[i], v = B[i];
		if (u == v) {
			if (u == 0) continue;
			if (u > 0) a++;
			else b++;
		} else if (u > v) x += u;
		else y += v;
	}
	if (x < y) swap(x, y);
	int k = min(x - y, b);
//	cerr << x <<" "<< y;
	x -= k;
	b -= k;
	if (b == 0) {
		k = min(x - y, a);
		a -= k;
		y += k;
		if (a == 0) cout << y << '\n';
		else cout << x + a / 2  << '\n';
	} else {
		if (a > b) cout << x + (a - b) / 2 << '\n';
		else cout << x - (b - a + 1) / 2 << '\n';
	}



}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	std::cin >> T;
	while (T--) solve();
	return 0;
}

E. Mathematical Problem

解析:

插入 n - 2 个运算符,说明至少要合并俩个数字,考虑合并字典序最小的俩个数字,但是注意如果有俩个数字第一个数相同,那么第二个数为1的反而更不优。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5;


inline void solve() {
	int n;
	cin >> n;
	string s;
	cin >> s;
	if (s.size() <= 2) {
		cout << stoi(s)  << '\n';
		return;
	}
	if (s[0] == '0' || s[n - 1] == '0') {cout << 0 << '\n';return;}
	else if (s.size() >= 4) {
        for(int i=1;i<n;i++){
			if(s[i]=='0') {cout << 0 << '\n';return;}
		}
	}
	ll res = 0;
	string t = "", ss = ""; //最小串,当前串
	t += s[0], t += s[1];
	ss = t;
	for (int i = 2; i < n; i++) {
		ss[0]=ss[1];
		ss[1]=s[i];
		if(t[1]=='1' && ss[0]==t[0]){
			 t=ss;
		}
		else {
			if(t[0]==ss[0] && ss[1]=='1') continue;
			if(ss<t) t=ss;
		}
	}
	int flag=0;
	for(int i=0;i<n;i++){
		if(i!=n-1 && s[i]==t[0] && s[i+1]==t[1] && !flag) {
			int tt=stoi(t);
			if(tt!=1) res+=tt;
			i++;
			flag=1;
		}
		else if(s[i]=='1'){
			continue;
		} 
		else res+=s[i]-'0';
	}
	if(res==0) res++;
	cout << res <<'\n';
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	std::cin >> T;
	while (T--) solve();
	return 0;
}

F. D-Function

解析:注意数据范围,此题需要O(1)去完成,逆元和快速幂不懂的自行百度哦

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N=1e5,p=1e9+7;

ll qpow(ll a,ll x){
	ll ans=1;
	while(x){
		if(x & 1) ans=ans * a %p;
		a=a*a%p;
		x>>=1;
	}
	return ans;
}
inline void solve() {
	int l,r,k; cin >> l >> r >> k;
	l++,r++;
    //注意到,对于满足条件的数,最大使用数字 i 满足 k*i<= 9
	//所以就是用 0-i 的所有数字 去填 l -- r-1 个空,保证第一个数不为0
	ll mx=9/k;
	if(mx<1) {
		cout << 0 << '\n';
		return ;
	}
	ll ans=0;
//	for(int i=l;i<r;i++){
//      分步乘法运算,先确定第一个数有 mx 种放法,后面每一个位置有  mx + 1 种放法
//		ans=(ans+qpow(mx+1,i-1)*mx)%p;
//	}
    // 设 l 位时的贡献是 x, l+1 位的贡献是 x * (mx+1) 等差数列求和
	// 答案即为 x * (1- qpow(mx+1,r-l))/(1-mx-1)
	// 注意逆元
	ans= qpow(mx+1,l-1)*mx%p;
	cout << ans*(qpow(mx+1,r-l)-1+p)%p*qpow(mx,p-2)%p << '\n';
}

int main() {
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
	std::cin >> T;
	while (T--) solve();
	return 0;
}

G. Game On Tree

解析:

        对于一个只有俩片叶子的树来说,其实就是一个瘦高的“人”字形树,我们首先建树,再判断一下起始点在头还是脚就可以了,这是一个很简单的根据奇偶性的博弈

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N=2e5+10;

vector<int>g[N];
inline void solve() {
	int n,t; cin >> n >> t;
	for(int i=1;i<n;i++){
		int u,v; cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	map<int,int>mp; //记录每一个节点的儿子的个数
	auto dfs=[&](auto self,int x, int pr)->int{
		int sum=0;
		for(auto i:g[x]){
			if(i==pr) continue;
			sum+=self(self,i,x)+1;
		}
		mp[x]=sum;
		return sum;
	};
	dfs(dfs,1,0);
	int st; cin >> st;
// 事实上 st 最多只有俩个子树,考虑左子树和右子树的大小即可
	int flag=0;
//	for(int i= 1;i<=n;i++) cout << mp[i] << ' ';
	if(mp[st]+1==n) {
		for(auto j:g[st]) if((mp[j]+1) & 1) flag=1;
	}
	else {
		int t=n-mp[st]-1;
		if(t & 1) flag=1;
		else if(mp[st] & 1) flag=1;
	}
	if(flag) cout << "Ron";
	else cout << "Hermione";
}

int main() {
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
//	std::cin >> T;
	while (T--) solve();
	return 0;
}

H.Turtle vs. Rabbit Race: Optimal Trainings

解析:

        对于一个左端点来说,越往右训练的节数肯定是单调增加的,所以我们可以二分找一个分界点,答案就是分界点的左右俩个数中的一个。

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N=1e5+10;

ll a[N],p[N];
inline void solve() {
	int n; cin >> n;
	for(int i=1;i<=n;i++) {
		cin >> a[i];
		p[i]=p[i-1]+a[i];
	}
	int q; cin >> q;
	while(q--){
		ll l,r=n,u; cin >> l >> u;
		// 我们要尽量找到一个以l为起点的子段,使得sum 尽可能的接近 u
		// 也就是 a[r + 1] +sum > u && sum - a[r] < u 的分界点
		// 我们可以通过预处理前缀和加二分的方式解决这个问题
		ll lr=l;
		while(lr+1<r){
			ll mid = lr+r >> 1;
			if(p[mid]-p[l-1]>u) r=mid;
			else lr=mid;
		}
		ll t=p[lr]-p[l-1],tt=p[r]-p[l-1];
		ll t1=(u+(u-t+1))*t/2,t2=(u+1)*u/2-(tt-u-1)*(tt-u)/2;
		if(t1>=t2) cout << lr << ' ';
		else cout << r << ' ';
	}
	cout << '\n';
}

int main() {
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
	std::cin >> T;
	while (T--) solve();
	return 0;
}

写在最后:

循序渐进,劳逸结合才是王道。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值