奋斗群群赛15总结与心得

总体感受

https://vjudge.net/contest/187045
蒟蒻就是蒟蒻,眼睁睁看着大佬一道一道A,我只能看看。

T1

题目

给夹克扣纽扣的时候必须保证要有一颗扣子是松开的,并且当该夹克只有一颗扣子的时候要扣上它。输入夹克的扣子数量和每颗扣子是否是扣上的,输出该扣扣子的方法是否是符合要求的。

思路

水题不用我多解释吧。我居然用了7次才A。当时我觉得我超级傻,输入了n之后直接开始判a[1]是0还是1。

#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[10000],n,i;
cin>>n;int s=0;
for (i=1;i<=n;i++)
  {
  cin>>a[i];
  if (a[i]==0) s++;
  }
if  (n==1&&a[1]==1)  return cout<<"YES",0;
else if (n==1) return cout<<"NO",0;
if (s>1||s==0) cout<<"NO";
else cout<<"YES";
}

T2

题目

给出一个由大小写英文字母组成的字符串,判断该字符串是否是回文的,是输出“TAK”,否则输出”NIE”.

思路

这题真的是坑。首先先找出自己就是左右对称的字母,OHXIMTUWYVAoxvw,然后找出左右对称的两对字母b,d和p,q.注意多出来一个角什么的是不对称的啊。比赛时没多想随手好几个if糊上去了。

#include<bits/stdc++.h>
using namespace std;
char duiyin(char c)
{
if (c=='b') return 'd';
else if (c=='d') return 'b';
else if (c=='p') return 'q';
else if (c=='q') return 'p';
else if (c=='o') return c;
else if (c=='H'||c=='X'||c=='x') return c;
else if (c=='I'||c=='M'||c=='O'||c=='T'||c=='U'||c=='W'||c=='Y'||c=='v'||c=='V'||c=='A'||c=='w') return c;
else return '0';
}
int main()
{
string s;
cin>>s;
for (int i=0;i<=s.size()-1;i++) if (s[i]!=duiyin(s[s.size()-i-1])) return cout<<"NIE",0;
cout<<"TAK";
}

T3

题目

输入一个实数,把它用科学计数法表示。

思路

可以看出这题很坑。先把前面的和后面的0去掉,看看非0数字有多少个,如果只有一个直接输出之以及10的乘方。如果有很多个先输出一个小数点,然后输出剩下的非零数,根据小数点的位置输出10的乘方。交的时候把bool变量b定义在主函数内又没有给它赋初值,codeforces默认它的初值是1,我在自己这里测试好好的,交到上面WA第一个点我还交了6次。

#include<bits/stdc++.h>
using namespace std;
const int boss=1e6;
char c[boss+10];
int main()
{
cin>>c;
int len=strlen(c),wei1=-1,wei2=len,point=len,i;bool b=0;//注意初始化
for (i=0;i<len;i++) 
  {
  if (c[i]!='.'&&c[i]!='0'&&b==0) {wei1=i;b=1;}//wei1为第一个不为0的数字的位置
  if (c[i]=='.') point=i;//小数点的位置
  if (c[i]!='0'&&c[i]!='.') wei2=i;//最后一个不为0的位置
  }
if (wei1==-1) return printf("0"),0;
else 
  {
  printf("%c",c[wei1]);
  if (wei2>wei1) printf(".");//小数点
  for (i=wei1+1;i<=wei2;i++) if (c[i]!='.') printf("%c",c[i]);//输出后面的数字
  } 
int e=0;
e=wei1<point?point-wei1-1:point-wei1;//判断10的乘方的数量
if (e!=0) printf("E%d",e);
}

T4

题目

给出一串1-n数列,又给出n组数对,每组数对可以任意互换,求换出字典序最大的数字序列.

思路

傻乎乎的我并没有意识到这题是个并查集,在下面暴力了好几次,WA了第8个点.呵呵.下面先暴力再给出并查集题解.

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int boss=1e6;
pii nico[boss+10];
int a[boss+10],b[boss+10],n,m;
bool cmp(pii a,pii b){return a.second<b.second;}
int main()
{
cin>>n>>m;
int i;
for (i=1;i<=n;i++) 
  {
  scanf("%d",&nico[i].first);
  nico[i].second=i;
  }
sort(nico+1,nico+n+1);//先按照first排,交换second,最后按second排,输出first
for (i=1;i<=m;i++)
  {
  scanf("%d%d",&a[i],&b[i]);
  if (a[i]>b[i]) swap(a[i],b[i]);
  if (nico[a[i]].second<nico[b[i]].second) swap(nico[a[i]].second,nico[b[i]].second);
  }
for (i=1;i<=m;i++) if (nico[a[i]].second<nico[b[i]].second) swap(nico[a[i]].second,nico[b[i]].second);
for (i=1;i<=m;i++) if (nico[a[i]].second<nico[b[i]].second) swap(nico[a[i]].second,nico[b[i]].second);
//......以下可以再重复很多很多次.
sort(nico+1,nico+n+1,cmp);
for (i=1;i<=n;i++) printf("%d ",nico[i].first);
}

呵呵.

#include<bits/stdc++.h>
using namespace std;
const int boss=1e6;
vector<int> number[boss+10],position[boss+10];
int p[boss+10],a[boss+10],answer[boss+10],father[boss+10];
int find(int x){return x==father[x]?x:father[x]=find(father[x]);}
int main()
{
int n,m,i,j,b;
cin>>n>>m;
for (i=1;i<=n;i++) 
  {
  scanf("%d",&a[i]);
  father[i]=i;
  p[i]=i;
  }
for (i=1;i<=m;i++)
  {
  int a;
  scanf("%d%d",&a,&b);
  a=find(a),b=find(b);
  if (a==b) continue;
  father[a]=b;
  }
for (i=1;i<=n;i++)
  {
  int x=find(i);
  position[x].push_back(i);
  number[x].push_back(-a[i]);//从大到小排,然而系统默认是从小到大的,所以把负数放进去就能从大到小排了.
  }
for (i=1;i<=n;i++) 
  {
  sort(number[i].begin(),number[i].end());
  for (j=0;j<position[i].size();j++) answer[position[i][j]]=-number[i][j];
  }
for (i=1;i<=n;i++) printf("%d ",answer[i]);
}

T6

题目

给n个数字,从里面选两个数字相乘,可以得到n*(n-1)个乘积.给出n个询问x,对于每个询问输出大于等于x的乘积数.

思路

利用桶存储,i和j都从0-3e6扫一遍,发现i*j>3e6就break,这样做的复杂度是nlogn,居然能应付得上.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int boss=3e6;
ll sum[boss+10]={0},num[boss+10]={0};
int main()
{
ll n,m,i,j,da=0;
cin>>n;
for (i=1;i<=n;i++) 
  {
  scanf("%I64d",&m);
  num[m]++;
  da=max(da,m);
  }
for (i=0;i<=da;i++)
  {
  for (j=0;j<=da;j++)
    {
    if (i*j>boss) break;
    sum[i*j]+=num[i]*num[j];
    if (i==j) sum[i*j]-=num[i]; 
    }
  }
for (i=1;i<=boss+1;i++) sum[i]+=sum[i-1];
scanf("%I64d",&m);
for (i=1;i<=m;i++) 
  {
  ll xunwen;
  scanf("%I64d",&xunwen);
  printf("%I64d\n",n*(n-1)-sum[xunwen-1]);
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值