1月30日刷题总结(第八届“图灵杯”)

1月30日刷题总结(第八届“图灵杯”)

T1:求数组中最长的能整除k的子数组

用前缀和a[]预处理数组,则从第i位到第j位的子串和为a[j]-a[i-1],又(a-b)%k=a%k-b%k,所以a[j]-a[i-1]整除k等价于a[j]a[i-1]k取模的结果相等,然后只需要贪心的寻找距离最远的相同取模结果即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
ll a[N],s[N];
map<ll,vector<ll> >mp;
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		ll n,k;
		scanf("%lld%lld",&n,&k);
		mp.clear();
		for(ll i=1;i<=n;i++){
			scanf("%d",&a[i]);
			s[i]=s[i-1]+a[i];
		}
		mp[0].push_back(0);
		for(int i=1;i<=n;i++){
			s[i]=s[i]%k;
			mp[s[i]].push_back(i);
		}
		ll ans=0;
		for(auto t:mp){
			ans=max(ans,t.second[t.second.size()-1]-t.second[0]);
		}
		if(ans==0) cout<<-1<<endl;
		else cout<<ans<<endl;
		
	}
}

T2:巴什博弈

**基本的巴什博弈:**一堆物品有n个,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。

结论:n%(m+1)==0则后手胜利

变形 :如果我们规定,最后取光者输,那么又如何考虑呢?

结论:(n - 1) % (m + 1)等于0时,后手胜,反之先手胜

本题就是变形的巴什博弈

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int n,k;
		cin>>n>>k;
		if((n-1)%(k+1)!=0) puts("yo xi no forever!");
		else puts("ma la se mi no.1!");
	}
}

T3:威佐夫博弈

有两堆石子,两个顶尖聪明的人在玩游戏,每次每个人可以从任意一堆石子中取任意多的石子或者从两堆石子中取同样多的石子,不能取得人输,分析谁会获得胜利

#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
using namespace std;
main()
{
    int a,b;
    scanf("%lld%lld",&a,&b);
    if(a>b) swap(a,b);
    int temp=abs(a-b);
    int ans=temp*(1.0+sqrt(5.0))/2.0;
    if(ans==a) printf("0");
    else 	   printf("1");
    return 0;
}

T4:stl的综合使用—成绩查询

注意学会用多个map存储多个信息

可以用set反查某个分数对应的人,而且set还有自动排序的功能

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
map<string,int> gc,sex,id;
set<string> ss[120];
int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		string name;
		int a,b,c;
		cin>>name>>a>>b>>c;
		gc[name]=a;
		sex[name]=b;
		id[name]=c;
		ss[a].insert(name);
	}
	int m;
	cin>>m;
	while(m--){
		int t;
		scanf("%d",&t);
		if(t==1){
			string name;
			cin>>name;
			cout<<gc[name]<<" "<<id[name]<<" "<<sex[name]<<endl;
		}else{
			int score;
			cin>>score;
			set<string>::iterator it;
			st=ss[score].begin();
			for(;it!=ss[score].end();it++){
				cout<<*it<<"\n";
			}
		}
	}
}

T5:找规律、打表

看到题目给的类似数学公式,有一种方法是找规律

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
ll qpow(ll m,ll n){
	ll res=1;
	while(n){
		if(n&1) res=res*m%mod;
		n=n>>1;
		m=m*m%mod;
	}
	return res;
}
int main(){

	int t;
	cin>>t;
	while(t--){
		ll n,m;
		cin>>n>>m;
		if(m==1){
			cout<<2*n%mod<<endl;
		}else if(m==2){
			cout<<qpow(2,n)%mod<<endl;
		}else if(m==0){
			if(n==1) cout<<n+1<<endl;
			else cout<<(n+2)%mod<<endl;
		}
	}
}

T6:天梯赛原题----直接模拟遍历图求最短路径

#include<bits/stdc++.h>
using namespace std;
const int N=305;
int g[N][N];
int r[N];
int main(){
	int n,m;
	cin>>n>>m;
	memset(g,0x3f,sizeof g);
	for(int i=0;i<m;i++){
		int a,b,w;
		cin>>a>>b>>w;
		g[a][b]=w;
		g[b][a]=w;
	}
	int k;
	cin>>k;
	int ans=0x3f3f3f3f;
	while(k--){
		int nn;
		cin>>nn;
		set<int> sc;
		for(int i=1;i<=nn;i++){
			cin>>r[i];
			sc.insert(r[i]);
		}
		if(sc.size()!=n){
			continue;
		}
		nn++;r[nn]=0;
		int now=0;
		int sum=0;
		int i;
		for(i=1;i<=nn;i++){
			if(g[now][r[i]]!=0x3f3f3f3f){
				sum+=g[now][r[i]];
				now=r[i];
			}else{
				break;
			}
		}
		if(i>nn){
			ans=min(ans,sum);
		} 
	}
	if(ans==0x3f3f3f3f) cout<<-1<<endl;
	else cout<<ans;
}

T7:用队列模拟

本题为简单的模拟题目,题目告知每四个字母和数字为一组,利用队列先进先出的特性,用循环遍历字

符串,将字母和数字分别存入到两个队列中,进行转换操作。输出答案。

#include<bits/stdc++.h>
using namespace std;
int main(){
	string s;
	cin>>s;
	queue<char> zimu;
	queue<int> shuzi;
	for(int i=0;i<32;i++){
		if(s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z'){
			zimu.push(s[i]);
		}else if(s[i]>='0' && s[i]<='9'){
			shuzi.push(s[i]-'0');
		}
	}
	string ans="";
	while(!zimu.empty()){
		string tmp;
		for(int i=1;i<=4;i++){
			tmp+=zimu.front();
			zimu.pop();
		}
		vector<int> v;
		for(int i=1;i<=4;i++){
			v.push_back(shuzi.front());
			shuzi.pop();
		}
		for(int i=0;i<4;i++){
			if(tmp[i]>'Z'){
				if(tmp[i]+v[i]>'z'){
					tmp[i]=tmp[i]+v[i]-'z'+'A';
				}else{
					tmp[i]+=v[i];
				}
			}else{
				if(tmp[i]+v[i]>'Z'){
					tmp[i]=tmp[i]+v[i]-'Z'+'a';
				}else{
					tmp[i]=tmp[i]+v[i];
				}
			}
		}
		reverse(tmp.begin(),tmp.end());
		ans+=tmp;
	}
	cout<<ans;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值