第八届“图灵杯”NEUQ-ACM程序设计竞赛个人赛
寒假打的一场比赛,时隔许久对这场比赛还有些许印象,所以特意回来补了这场比赛的题目。
小宝的幸运数组(B题)
题目链接
#include <iostream>
#include <cstring>
using namespace std;
#define N 100005
int number[N],sum[N],pos[N];
int main()
{
int _;
cin >> _;
while(_--)
{
memset(sum,0,sizeof(sum));
memset(pos,-1,sizeof(pos));
int n,k;
cin >> n >> k;
for(int i=1;i<=n;i++)
cin >> number[i];
pos[0]=0;
int ans=-1;
for(int i=1;i<=n;i++)
{
sum[i]=(sum[i-1]+number[i])%k;
if(pos[sum[i]]==-1)
pos[sum[i]]=i;
else
ans=max(ans,i-pos[sum[i]]);
}
cout << ans << endl;
}
return 0;
}
前缀和求余直接模拟即可。
上进的凡凡(C题)
题目链接
#include <iostream>
using namespace std;
#define N 100005
int number[N];
int main()
{
int n;
cin >> n;
for(int i=1;i<=n;i++)
cin >> number[i];
number[n+1]=-1;
long long ans=0,cnt=1;
for(int i=2;i<=n+1;i++)
{
if(number[i]>=number[i-1])
cnt++;
else
{
ans+=cnt*(cnt+1)/2;
cnt=1;
}
}
cout << ans << endl;
return 0;
}
直接模拟即可。
Seek the Joker I(D题)
题目链接
一看出题人就是老柚子厨了,题目背景来自柚子社创立十周年纪念作《千恋万花》,是一款和风gal。没玩过《千恋万花》也没关系,题目的大意就是芳乃酱和丛雨酱在博弈,芳乃酱yyds!!!
声明:本题中的所有角色在剧情发生时均已超过18岁。(众所周知柚子社作品老十八禁了)
#include <iostream>
using namespace std;
int main()
{
int _;
cin >> _;
while(_--)
{
int n,k;
cin >> n >> k;
if((n-1)%(k+1))
cout << "yo xi no forever!" << endl;
else
cout << "ma la se mi no.1!" << endl;
}
return 0;
}
回到题目本身,这是一道典型的巴什博弈题目。巴什博弈的根本是破坏对方的目的以达到自己的目的。由于芳乃酱先手且拿到最后一张牌的人输,那么芳乃酱的任务就是在自己的回合内将剩下的n-1张牌拿光,这样才能获胜。我们称丛雨酱和芳乃酱各拿一次牌为一个回合,那么可以保证一回合内只要芳乃酱愿意且牌足够的情况下,这一个回合就一定能够拿完k+1张牌,所以只要剩下的n-1张牌对k+1求余还有余数的情况下,芳乃酱就一定能够获胜,只要芳乃酱第一次拿(n-1)%(k+1)张牌,经过(n-1)/(k+1)轮之后,就只剩下一张牌且轮到丛雨酱去抽,所以芳乃酱就一定会获胜。反之,如果(n-1)%(k+1)为0的话,芳乃酱就一定会输,因为不能拿0张牌。
成绩查询ing(F题)
题目链接
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
struct Stu
{
int grade;
int id;
int gender;
};
map <string,Stu> mp1;
map <int,vector <string> > mp2;
string ans[105];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;
cin >> n;
while(n--)
{
string name;
int grade,gender,id;
cin >> name >> grade >> gender >> id;
mp1[name]={grade,id,gender};
mp2[grade].push_back(name);
}
for(auto i:mp2)
{
auto f=i.first;
auto s=i.second;
sort(s.begin(),s.end());
for(int i=0;i<s.size();i++)
ans[f]+=s[i]+'\n';
}
int m;
cin >> m;
while(m--)
{
int opt;
cin >> opt;
if(opt==1)
{
string name;
cin >> name;
cout << mp1[name].grade << " " << mp1[name].id << " " << mp1[name].gender << endl;
}
if(opt==2)
{
int grade;
cin >> grade;
cout << ans[grade];
}
}
return 0;
}
典型的考察数据结构的题目,题目的难点是处理这两个查询,查询一可以用一个<string,sturct>类型的map来解决,查询二可以用一个<int,vector>类型的map来解决,注意看这里处理第二个map的代码,将第二个map里的元素提前按字典序sort好存在string型的数组里,方便查询,这样一来,查询一所用的时间是O(logn),查询二所用的时间是O(1)。
买花(I题)
题目连接
#include <iostream>
#include <cmath>
using namespace std;
int sum[20];
int main()
{
for(int i=1;i<=15;i++)
sum[i]=pow(2,i)-1;
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
int flag=0;
for(int i=2;i<=15;i++)
{
if(n%sum[i]==0)
{
flag=1;
break;
}
}
if(flag)
cout << "YE5" << endl;
else
cout << "N0" << endl;
}
return 0;
}
将2的幂次方减1提前打好表,每输入一个数,就跑循环判断它是否是这些表中的数的倍数,如果是则输出“YE5”,都不是则输出“N0”。
这是一题简单的模拟
题目链接
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 305
#define INF 0x7fffffff
int mp[N][N],number[2*N],vis[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
while(m--)
{
int u,v,cost;
scanf("%d%d%d",&u,&v,&cost);
mp[u][v]=cost;
mp[v][u]=cost;
}
int k;
scanf("%d",&k);
int flag=0,ans=INF;
while(k--)
{
memset(vis,0,sizeof(vis));
int num;
scanf("%d",&num);
for(int i=1;i<=num;i++)
scanf("%d",&number[i]);
number[0]=number[n+1]=0;
if(num!=n)
continue;
else
{
int i,sum=0;
for(i=0;i<=num;i++)
{
if(vis[number[i]]||!mp[number[i]][number[i+1]])
break;
vis[number[i]]=1;
sum+=mp[number[i]][number[i+1]];
}
if(i>num)
flag=1,ans=min(ans,sum);
}
}
if(!flag)
printf("-1\n");
else
printf("%d\n",ans);
return 0;
}
题目确实是一道模拟题,按照题目给出的要求一个一个去模拟即可,数据量较小(300),直接开二维数组跑。
黑洞密码(K题)
题目链接
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string s;
cin >> s;
string s1,s2;
for(int i=0;i<32;i++)
{
if(s[i]>='A'&&s[i]<='Z'||s[i]>='a'&&s[i]<='z')
s1+=s[i];
else
s2+=s[i];
}
for(int i=0;i<16;i++)
{
if(s1[i]>='A'&&s1[i]<='Z')
{
s1[i]+=s2[i]-'0';
if(s1[i]>=91)
s1[i]+=7;
}
else
{
s1[i]-=32;
s1[i]+=s2[i]-'0';
if(s1[i]>=91)
s1[i]-=57;
s1[i]+=32;
}
}
reverse(s1.begin(),s1.begin()+4);
reverse(s1.begin()+4,s1.begin()+8);
reverse(s1.begin()+8,s1.begin()+12);
reverse(s1.begin()+12,s1.begin()+16);
cout << s1 << endl;
return 0;
}
模拟题可真不少,这道题也是按要求模拟即可,要求还不少,要求‘z’之后是‘B’,‘Z’之后是‘b’,有些小麻烦。要注意到如果给‘z’加上一个个位数是有可能超出char的上限的,所以如果是小写字母的话可以先减去一个32让其变成大写字母来处理,最后再加上32变回去。
建立火车站(L题)
题目链接
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 100005
long long number[N],dis[N];
int main()
{
int n,k;
cin >> n >> k;
for(int i=1;i<=n;i++)
cin >> number[i];
sort(number+1,number+1+n);
for(int i=1;i<n;i++)
dis[i]=number[i+1]-number[i];
long long Max=0;
for(int i=1;i<n;i++)
if(dis[i]>Max)
Max=dis[i];
long long l=1,r=Max;
while(l<r)
{
long long m=(l+r)/2;
long long sum=0;
for(int i=1;i<n;i++)
sum+=ceil((double)dis[i]/m)-1;
if(sum<=k)
r=m;
else
l=m+1;
}
cout << l << endl;
return 0;
}
很容易想到这道题是二分答案,需要注意用floor和ceil函数的时候一定要先转换成double型再调用函数,要不然一直WA,之前就在这里犯过错这次又犯了……二分答案还是没啥好说的,直接做就可以了,关键就是这个边界的问题,每道题跟每道题都略有不同,自己还判断不出来,只能一点一点撞,啊这。