今天是我们夏令营入营的第一天,我们主要是讲了一下学过的算法,然后就是入营测试了。
第一题:音阶
题目大意:
给出一串旋律,判断是a小调还是C大调。判断方法,ADE分为a小调,CFG分为C大调。把这串旋律的每个音节的第一个字母取出,看一下是分为a小调的多还是C大调的多(哪个多就是哪种调)如果一样多,那么看旋律的最后一个音是a小调就是a小调,否则就是C大调。
题目分析:
就是找旋律中开头字母和每一个音节分隔符‘|’后的第一个字母,统计哪种多。注意:如果是一样的话,那么要找最后一个音而不是最后一节的第一个音。
参考代码:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
ifstream fin("ljestvica.in");
ofstream fout("ljestvica.out");
#define cin fin
#define cout fout
string s;
int cntA,cntC;
void pd(char c)
{
if(c=='A' || c=='D' || c=='E') cntA++;
else cntC++;
return ;
}
int main()
{
cin>>s;
pd(s[0]);
int len=s.size();
for(int i=1;i<len;i++)
if(s[i]=='|') pd(s[i+1]);
if(cntA==cntC) pd(s[len-1]);
if(cntA>cntC) cout<<"A-mol"<<endl;
if(cntA<cntC) cout<<"C-dur"<<endl;
return 0;
}
第二题:波老师
题目大意:
t组数据
在平面直角坐标系中,有n个点。问是否存在两个点的曼哈顿距离与另两个点的曼哈顿距离相等。
//曼哈顿距离:两点之间绝对轴距总和
数据范围:
80% 1≤n≤1000 点坐标1≤Xi≤m 1≤m≤1000
100% 1≤t≤50 1≤n≤100000 点坐标 1≤Xi≤m 1≤m≤100000
题目分析:
先说80%的水分。就是枚举每两个点之间的曼哈顿距离,在判断有没有相同的。时间复杂度 o(t*n^2)
100%数据,就要用到抽屉原理。我们用一个桶把所有枚举到的曼哈顿距离存起来。然后搜一个就判断一次,找到后就立刻退出来。那么最多有2m种距离。所以搜到第2m+1种时,就必定至少有两个重复。所以时间复杂度为o(t*2m)
参考代码:
#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
using namespace std;
ifstream fin("teacher.in");
ofstream fout("teacher.out");
#define cin fin
#define cout fout
int t,n,m;
struct Tnode
{
int x,y;
};
Tnode a[100001];
bool f[200001];
bool cmp(Tnode x,Tnode y)
{
if(x.x<y.x) return true;
if(x.x>y.x) return false;
if(x.y<y.y) return true;
return false;
}
int main()
{
cin>>t;
while(t>0)
{
bool pd=0;
for(int i=0;i<=200000;i++) f[i]=0;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>a[i].x>>a[i].y;
// sort(a,a+n,cmp);
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
if(f[abs(a[j].x-a[i].x)+abs(a[j].y-a[i].y)])
{
pd=1;
break;
}
f[abs(a[j].x-a[i].x)+abs(a[j].y-a[i].y)]=1;
}
if(pd) break;
}
if(pd) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
t--;
}
return 0;
}
第三题:爆裂吧世界
题目大意:
给你一个长度为n的数列A,请你计算里面有多少个四元组(a,b,c,d)满足:
a≠b≠c≠d,1≤a﹤b≤n,1≤c﹤d≤n,Aa﹤Ab,Ac>Ad
数据范围:
15% n<=100
100% n<=50000
A在int范围里
题目分析:
15%的水分自然就是爆搜,n^4 4重循环加上标记就过了
100%枚举每一个数,通过离散化用线段树或者树状数组维护求这个数左右的比它大或小的(可与他组合)的数数量,算出总数后用容斥原理减去重复部分即可算出答案。
参考代码:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
using namespace std;
ifstream fin("world.in");
ofstream fout("world.out");
#define cin fin
#define cout fout
int n;
struct Tnode
{
int x,y;
};
Tnode a[50007];
int f[50007];
int p[50007];
int s1[50007],s2[50007],b1[50007],b2[50007];
bool cmp(Tnode x,Tnode y)
{
if(x.x<y.x) return true;
return false;
}
void add(int pos)
{
for(int i=pos;i<=n;i+=(i&(-i)))
f[i]++;
}
int sum(int pos)
{
int s=0;
for(int i=pos;i>0;i-=(i&(-i)))
s+=f[i];
return s;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].x,a[i].y=i;
sort(a+1,a+n+1,cmp);
int now=0;
for(int i=1;i<=n;i++)
{
if(a[i].x!=a[i-1].x) now++;
p[a[i].y]=now;
}
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
s1[i]=sum(p[i]-1);
b1[i]=i-1-sum(p[i]);
add(p[i]);
}
memset(f,0,sizeof(f));
for(int i=n;i>=1;i--)
{
s2[i]=sum(p[i]-1);
b2[i]=n-i-sum(p[i]);
add(p[i]);
}
long long ans1,ans2,ans3;
ans1=ans2=ans3=0;
for(int i=1;i<=n;i++)
ans1+=s1[i];
for(int i=1;i<=n;i++)
ans2+=b1[i];
ans3=ans1*ans2;
for(int i=1;i<=n;i++)
{
ans3-=s1[i]*b1[i];
ans3-=s1[i]*s2[i];
ans3-=s2[i]*b2[i];
ans3-=b1[i]*b2[i];
}
cout<<ans3<<endl;
return 0;
}