XJOI奋斗群 群赛15解题报告
原题
https://cn.vjudge.net/contest/187045#overview (Educational Codeforces Round 14)
A - Fashion in Berland
题意
有一串01序列,除非只有一个数,否则若只有一个0,输出“YES”,反之输出“NO”。
题解
简单的计数,特判n=1的情况。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
int a[1010],cnt=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==1) cnt++;
}
if((cnt==n-1&&n!=1)||(n==1&&cnt==1)) cout<<"YES";
else cout<<"NO";
}
B - s-palindrome
题意
给出一串字符串,如果字符串左右完全对称,输出”YES“,否则输出”NO”。
题解
从0-字符串长度除以2处依次枚举当前位置的字符,再分类判断,题目本身不难,但判断哪一个字符是对称的有点坑2333.
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s;
int n=s.length();
for(int i=0;i<=n/2;i++){
if((s[i]=='A'||s[i]=='H'||s[i]=='I'||s[i]=='M'||s[i]=='O'||s[i]=='T'||s[i]=='U'||s[i]=='V'||s[i]=='W'||s[i]=='X'||s[i]=='Y')&&s[i]==s[n-i-1]) continue;
else if((s[i]=='w'||s[i]=='v'||s[i]=='o'||s[i]=='x')&&s[i]==s[n-i-1]) continue;
else if(s[i]=='b'&&s[n-i-1]=='d') continue;
else if(s[i]=='p'&&s[n-i-1]=='q') continue;
else if(s[i]=='d'&&s[n-i-1]=='b') continue;
else if(s[i]=='q'&&s[n-i-1]=='p') continue;
else {
cout<<"NIE";
return 0;
}
}
cout<<"TAK";
}
C - Exponential notation
题意
输入一串字符串代表一个数字(可能有前后导零),输出这个数字用科学计数法表示的结果。
题解
第一眼看到这题还以为是思维题,然后就记录了小数点的位置去分类讨论,做了好久才做出来。应该有比较好的构造解法,这里贴出我的分类AC代码。
#include<bits/stdc++.h>
using namespace std;
int main(){
bool flag1=false,dian=false;
string s;
cin>>s;
int n=s.length();
int pos=-1;
int t1=0,t2=0;
for(int i=0;i<n;i++){
if(s[i]=='.'){
pos=i;
dian=true;
}
if(pos==-1&&s[i]!='0') t1++;
if(pos!=-1&&i!=pos&&s[i]!='0') t2++;
}
if(t1==0&&t2==0) cout<<0;
else if(!dian){
int cnt1=0,cnt2=0;
for(int i=0;i<n;i++){
if(s[i]=='0') cnt1++;
else break;
}
for(int i=n-1;i>=0;i--){
if(s[i]=='0') cnt2++;
else break;
}
for(int i=cnt1;i<n-cnt2;i++){
cout<<s[i];
if(i==cnt1&&cnt1!=n-cnt2-1) cout<<".";
}
if(n-1-cnt1!=0)cout<<"E"<<n-1-cnt1;
}
else if(pos==n-1){
int cnt1=0,cnt2=0;
for(int i=0;i<n;i++){
if(s[i]=='0') cnt1++;
else break;
}
for(int i=n-2;i>=0;i--){
if(s[i]=='0') cnt2++;
else break;
}
for(int i=cnt1;i<=n-cnt2-2;i++){
cout<<s[i];
if(i==cnt1&&cnt1!=n-cnt2-2) cout<<".";
}
if(n-2-cnt1!=0)cout<<"E"<<n-2-cnt1;
}
else if(t2==0){
int cnt1=0,cnt2=0;
for(int i=0;i<pos;i++){
if(s[i]=='0') cnt1++;
else break;
}
for(int i=pos-1;i>=0;i--){
if(s[i]=='0') cnt2++;
else break;
}
for(int i=cnt1;i<pos-cnt2;i++){
cout<<s[i];
if(i==cnt1&&cnt1!=pos-cnt2-1) cout<<".";
}
if(pos-1-cnt1!=0)cout<<"E"<<pos-1-cnt1;
}
else if(pos==0){
int cnt1=0,cnt2=0;
for(int i=1;i<n;i++){
if(s[i]=='0') cnt1++;
else break;
}
for(int i=n-1;i>=0;i--){
if(s[i]=='0') cnt2++;
else break;
}
for(int i=1+cnt1;i<n-cnt2;i++){
cout<<s[i];
if(i==cnt1+1&&n-cnt2-1!=cnt1+1) cout<<".";
}
if(cnt1+1!=0)cout<<"E-"<<cnt1+1;
}
else if(t1==0){
int cnt1=0,cnt2=0;
for(int i=pos+1;i<n;i++){
if(s[i]=='0') cnt1++;
else break;
}
for(int i=n-1;i>pos;i--){
if(s[i]=='0') cnt2++;
else break;
}
for(int i=pos+cnt1+1;i<n-cnt2;i++){
cout<<s[i];
if(i==cnt1+pos+1&&n-cnt2-1!=cnt1+pos+1) cout<<".";
}
if(cnt1+1!=0)cout<<"E-"<<cnt1+1;
}
else{
int cnt1=0,cnt2=0;
for(int i=0;i<pos;i++){
if(s[i]=='0') cnt1++;
else break;
}
for(int i=n-1;i>=pos+1;i--){
if(s[i]=='0') cnt2++;
else break;
}
for(int i=cnt1;i<pos;i++){
cout<<s[i];
if(i==cnt1) cout<<".";
}
for(int i=pos+1;i<n-cnt2;i++){
cout<<s[i];
}
if(pos-1-cnt1!=0)cout<<"E"<<pos-1-cnt1;
}
}
D - Swaps in Permutation
题意
有n个数字和m种交换方法,每一种方法可以将索引为a的数字与索引为b的数字交换,交换次数没有限制,问最后能交换成的字典序最小的序列。
题解
比较简单的并查集,但因为比较字典序部分耗时比较多,虽然给了5秒,不优化仍然会TLE,因此需要对并查集进行优化,用vector或优先队列都可以,这里贴出我用优先队列优化的AC代码。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000010;
int p[MAXN],fa[MAXN],ans[MAXN],num[MAXN];
int n,m,a,b,root,cnt;
priority_queue <int> que1[MAXN],que2[MAXN];
bool visit[MAXN];
int find(int x){
if(fa[x]!=x) {
fa[x]=find(fa[x]);
}
return fa[x];
}
void usd(int a,int b){
int temp1=find(a),temp2=find(b);
if(temp1!=temp2){
fa[temp1]=temp2;
}
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
fa[i]=i;
scanf("%d",&p[i]);
}
for(int i=1;i<=m;i++){
scanf("%d %d",&a,&b);
usd(a,b);
// usd(b,a);
}
for(int i=1;i<=n;i++){
root=find(i);
if(!visit[root]){
num[++cnt]=root;
visit[root]=1;
}
que1[root].push(p[i]);
que2[root].push(-i);
}
for(int i=1;i<=cnt;i++){
while(!que1[num[i]].empty()){
ans[-que2[num[i]].top()]=que1[num[i]].top();
que1[num[i]].pop();
que2[num[i]].pop();
}
}
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}
}
F - Couple Cover
题意
有n个数与m组询问,从n个数中任取两个数相乘,问能有几种组合使得乘积大于等于询问数,对于每组询问输出一个答案。
题解
拿到题目首先想到可能是前缀之类的预处理,因为询问数很多并且询问本身并不大,因此可以暴力预处理出当前序列中小于等于当前值的数量有多少,之后对于每一组询问输出总数减前一个即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int MAXN=3000010;
ll a,n,m,q;
ll cnt[MAXN]={0},ans[MAXN]={0};
ll num;
void init(){
scanf("%I64d",&n);
for(int i=0;i<n;i++){
scanf("%I64d",&a);
cnt[a]++;
}
for(int i=1;i*i<MAXN;i++){
for(int j=i;i*j<MAXN;j++){
if(i==j) ans[i*j]+=cnt[i]*(cnt[i]-1);
else ans[i*j]+=2*cnt[i]*cnt[j];
}
}
for(int i=MAXN-2;i>=1;i--){
ans[i]+=ans[i+1];
}
num=(ll)n*(n-1)-ans[1];
}
int main(){
init();
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%I64d",&q);
printf("%I64d\n",ans[q]+num);
}
return 0;
}