奋斗群群赛—15,16
群赛15:
T1:Fashion in Berland
题目位置:
题意:
就是给你一个 01串,让你找出是否这个串只有一个 0 ,如果是,输出”YES”,不然就是输出”NO”!但是只有一个纽扣的时候要进行特判,必须是只有1的串(给题意杀了……)
AC代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,ans=0;
scanf("%d",&n);
if(n==1)
{
int y;
scanf("%d",&y);
if(y==0)
cout<<"NO";
else
cout<<"YES";
return 0;
}
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
if(x==0)
ans++;
}
if(ans==1)
cout<<"YES";
else
cout<<"NO";
return 0;
}
T2:s-palindrome
题目位置:
题意:
就是问你这一串英文字母是不是能够在”镜子”的照应之下,是和原来是对应一半相等的?
其实就是一个大模拟!
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N=1005;
char s[N];
int check(char x,char y)
{
if(x=='A'&&y=='A')
return 1;
if(x=='H'&&y=='H')
return 1;
if(x=='I'&&y=='I')
return 1;
if(x=='M'&&y=='M')
return 1;
if(x=='O'&&y=='O')
return 1;
if(x=='T'&&y=='T')
return 1;
if(x=='U'&&y=='U')
return 1;
if(x=='V'&&y=='V')
return 1;
if(x=='W'&&y=='W')
return 1;
if(x=='X'&&y=='X')
return 1;
if(x=='Y'&&y=='Y')
return 1;
if(x=='o'&&y=='o')
return 1;
if(x=='v'&&y=='v')
return 1;
if(x=='w'&&y=='w')
return 1;
if(x=='x'&&y=='x')
return 1;
if(x=='b'&&y=='d')
return 1;
if(x=='d'&&y=='b')
return 1;
if(x=='p'&&y=='q')
return 1;
if(x=='q'&&y=='p')
return 1;
return 0;
}
int main()
{
//string s;
scanf("%s",s+1);
int len=strlen(s+1);
int ans=0;
for(int i=1; i<=len/2; i++)
{
ans+=check(s[i],s[len-i+1]);
}
if(len%2==1)
{
int l=len/2+1;
ans+=check(s[l],s[l]);
if(ans==1+len/2)
cout<<"TAK";
else
cout<<"NIE";
}
else
{
if(ans==len/2)
cout<<"TAK";
else
cout<<"NIE";
}
return 0;
}
T3: Exponential notation
题目位置:
题意:
就是让你讲一个数字,变成 x*pow(10,n)形式,比如
input
16
output
1.6E1
input
01.23400
output
1.234
input
.100
output
1E-1
input
100.
output
1E2
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
char s[N];
int main()
{
scanf("%s",s+1);
int n=strlen(s+1);
int sep=n+1,sta=1,end=n;
int flag=0;
for(int i=1; i<=n; i++)
{
if(s[i]=='.')
sep=i;
if((s[i]=='0'||s[i]=='.')&&flag==0)
{
sta=i+1;
}
else if (s[i]>'0'&&s[i]<='9')
{
flag=1;
}
}
flag=0;
for(int i=n; i>=1; i--)
{
if((s[i]=='0'||s[i]=='.')&&flag==0)
{
end=i-1;
}
else if (s[i]!='0')
{
flag=1;
}
}
//cout<<sep<<" "<<sta<<" "<<end<<endl;
int r=end-sep,l;
if(sep<sta)
{
l=sep-sta;
}
else
{
l=sep-sta-1;
}
int p=0;
for(int i=sta+1; i<=end; i++)
{
if(s[i]!='0')
p=1;
}
printf("%c",s[sta]);
if(p==1) cout<<'.';
if(p)
{
for(int i=sta+1; i<=end; i++)
{
if(s[i]!='.')
printf("%c",s[i]);
}
}
if(l!=0)
{
printf("E");
printf("%d",l);
}
}
T4:Swaps in Permutation
题目位置
题意:
给一个数列,现在可以交换ai和bi,问能得到的最大的字典序的数列是什么
还有就是a->b,b->c那么 a->c啊!所以就是可以用到一个并查集的工作!
AC代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
using namespace std;
const int N=1000005;
int fa[N],a[N];
int n,m;
vector<int> value[N];
vector<int> order[N];
int find(int a)
{
return fa[a] ==a ?a : fa[a]= find(fa[a]);
}
int add(int x,int y)
{
fa[find(x)] = find(y);
}
int main()
{
//greater<int> ¾ÍÊǽ«Öµ´ÓСµ½´ó½øÐÐÒ»´Î ÅÅÐò!
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
fa[i]=i;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
for(int i=1; i<=m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1; i<=n; i++)
{
int root=find(i);
order[root].push_back(i);
value[root].push_back(a[i]);
}
for(int i=1; i<=n; i++)
{
sort(value[i].begin(),value[i].end(),greater<int>());
sort(order[i].begin(),order[i].end());
for(int j=0; j<value[i].size(); j++)
{
a[order[i][j]]=value[i][j];
}
}
for(int i=1; i<=n; i++)
printf("%d ",a[i]);
return 0;
}
T5:Xor-sequences
题目位置:
题意:
给定序列,从序列中选择k(1≤k≤1e18)个数(可以重复选择),使得得到的排列满足xi与xi+1异或的二进制表示中1的个数是3的倍数。问长度为k的满足条件的 序列有多少种?
思路:
矩阵快速幂!
AC代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int mod=1000000007;
ll m,a[1005];
int n,ans;
struct number
{
int edge[110][110];
number()
{
memset(edge,0,sizeof(edge));
}
} ANS,K,FIN;
number operator * (number ANS,number K)
{
number res;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++)
res.edge[i][j]=(ll)(res.edge[i][j]+(ll)ANS.edge[i][k]*K.edge[k][j]%mod)%mod;
}
return res;
}
int main()
{
scanf("%d%I64d",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%I64d",&a[i]);
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
ll x;
int cnt=0;
x=a[i]^a[j];
while(x)
{
cnt+=x&1;
x>>=1;
}
if(cnt%3==0)
K.edge[i][j]=1;
}
m--;
for(int i=1; i<=n; i++)
ANS.edge[i][i]=1;
while(m)
{
if(m&1)
{
ANS=ANS*K;
}
K=K*K;
m>>=1;
// cout<<m<<endl;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
ans=(ans+ANS.edge[i][j])%mod;
}
printf("%d\n",ans%mod);
return 0;
}
反思:
就是在看见了1e18的数据的时候就是想到一定是用log的算法来完成它,所以就是要想到快捷的方法,于是就是矩阵快速幂!
T6:Couple Cover
题目位置:
题意:
就是问你在一个序列里面,有多少对数的积是大于等于p 的?
有多组询问!
思路:
如果简单的枚举会十分的困难,肯定会TLE,但是其实这道题目的数据会有许多重复的,所以只要用一个桶来装这些数字,在预处理一下就好了,(正难则反)只要看有多少是小于p的而且有多少是总的,减一下就好了!
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N=3000005;
long long n;
long long num[N],qus[N];
int main()
{
int m;
scanf("%I64d",&n);
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
num[x]++;
}
for(int i=1; i*i<N; i++)
for(int j=i; i*j<N; j++)
{
if(i==j)
qus[i*i]+=num[i]*(num[i]-1);
else
qus[i*j]+=num[i]*num[j]*2;
}
for(int i=0; i<N; i++)
{
qus[i]+=qus[i-1];
}
//que[N-1]?a¡Á????a
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
int x;
scanf("%d",&x);
long long ans=n*(n-1)-qus[x-1];
printf("%I64d\n",ans);
}
}