1月30日刷题总结(第八届“图灵杯”)
文章目录
- T1:[求数组中最长的能整除k的子数组](https://ac.nowcoder.com/acm/contest/11746/B)
- T2:[巴什博弈](https://ac.nowcoder.com/acm/contest/11746/D)
- T3:[威佐夫博弈](https://ac.nowcoder.com/acm/contest/11746/E)
- T4:[stl的综合使用---成绩查询](https://ac.nowcoder.com/acm/contest/11746/F)
- T5:[找规律、打表](https://ac.nowcoder.com/acm/contest/11746/H)
- T6:[天梯赛原题----直接模拟遍历图求最短路径](https://ac.nowcoder.com/acm/contest/11746/J)
- T7:[用队列模拟](https://ac.nowcoder.com/acm/contest/11746/K)
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;
}