第一题:
题意:字符串用”|”分隔为一个个小结,统计每一小节第一个字母分别属于{ADE}和{CFG}的次x1、x2。
若x1>x2,输出A-mol
若x2>x1输出C-dur
若x1=x2 则用字符串最后一个字母属性来决定。
分析:直接模拟。
程序:
#include <cstdio>
#include <cstring>
int main()
{
freopen("ljestvica.in","r",stdin);
freopen("ljestvica.out","w",stdout);
char s[1000],t[1000];
scanf("%s",&s);
int move=0,Am=0,Cd=0;
int L;
s[strlen(s)]='|';
for (int i=0;i<strlen(s);i++)
{
if (s[i]=='|') {
if (t[0]=='A'||t[0]=='D'||t[0]=='E') Am++;
if (t[0]=='C'||t[0]=='F'||t[0]=='G') Cd++;
L=move-1; move=0;
} else {
t[move++]=s[i];
}
}
if (Am>Cd||(Am==Cd&&(t[L]=='A'||t[L]=='D'||t[L]=='E'))) printf("A-mol\n");
else printf("C-dur\n");
return 0;
}
第二题:
题意:给出N个点(Xi,Yi)。求是否存在四个点(A,B,C,D)(A< B,C< D,A≠C或者B≠D),使AB之间的曼哈顿距离和CD之间的曼哈顿距离相等。(0< Xi,Yi< =10^5)
分析:注意曼哈顿距离就是|Xi-Xj|+|Yi-Yj|。
暴力:用O(N^2)的方法求出任意两点的距离L (L<2*10^5),并以其为下标记录。若有重复标记则存在,否则不存在。
这种方法不会超时,因为点之间可能的曼哈顿距离种数最多只有2*10^5。(容斥原理)
程序:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=500000;
struct Point
{
int x,y;
}dots[maxn];
int n,m;
bool cmp(const Point &a,const Point &b) //点的排序
{
return (a.x<b.x||a.x==b.x&&a.y<b.y);
}
int dist(const Point a,const Point b) //求曼哈顿距离
{
return abs(a.x-b.x)+abs(a.y-b.y);
}
int main()
{
freopen("teacher.in","r",stdin);
freopen("teacher.out","w",stdout);
int T; scanf("%d",&T);
bool a[maxn*2];
while (T--)
{
scanf("%d%d",&n,&m);
for (int i=0;i<n;i++) scanf("%d%d",&dots[i].x,&dots[i].y);
sort(dots,dots+n,cmp); int Len=-1;
memset(a,false,sizeof(a)); bool flag=false;
for (int i=0;i<n-1;i++)
{
for (int j=i+1;j<n;j++) {
int k=dist(dots[i],dots[j]);
if (a[k]) { flag=true; break; } else a[k]=true;
}
if (flag) { printf("YES\n"); break; }
}
if (!flag) printf("NO\n");
}
return 0;
}
第三题:
题意:一个长度为n的数列A,计算里面有多少个四元组(a,b,c,d)满足:
a≠b≠c≠d,1≤a< b≤n,1≤c< d≤n,Aa< Ab,Ac>Ad
分析:
求出每一个数左右两边比自己小或大的个数(树状数组),即合法的(a,b)组合个数和(c,d)组合个数。总数之积则为合法四元组(a,b,c,d)的个数。(乘法原理)
因为a≠b≠c≠d,所以就要去掉a=b(不可能),c=d(不可能),a=c,b=c,a=d,b=d几种情况。Small为比自己小的个数,Big为比自己大的个数。1为左边,2为右边。
见图:(左右表示位置关系,高低表示ab之间和cd之间的大小关系)
程序:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include <iostream>
using namespace std;
const int maxdot=1000005;
int n;
int b[maxdot];
long long big1[maxdot],small1[maxdot];
long long big2[maxdot],small2[maxdot];
long long tree[maxdot];
struct Tnode
{
int x,y;
} a[maxdot];
void in(int x) //树状数组以数为下标添加标记
{
for (int i=x;i<=n;i=i+(i-(i&(i-1))))
{
tree[i]++;
}
}
int ask(int x) //求和方式求出1-x标记数(小于)
{
int re=0;
for (int i=x;i!=0;i=i&(i-1))
{
re+=tree[i];
}
return re;
}
bool cmp(Tnode a,Tnode b)
{
return a.x<b.x;
}
void solve()
{
for (int i=1;i<=n;i++) {scanf("%d",&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 ((i==1) || (a[i].x!=a[i-1].x)) now++;
b[a[i].y]=now;
}
memset(tree,0,sizeof(tree));
for (int i=1;i<=n;i++)
{
small1[i]=ask(b[i]-1); //查询
big1[i]=(i-1)-ask(b[i]); //求大于
in(b[i]); //添加标记
}
memset(tree,0,sizeof(tree));
for (int i=n;i>=1;i--) //反向求c,d
{
small2[i]=ask(b[i]-1);
big2[i]=(n-i)-ask(b[i]);
in(b[i]);
}
long long ans=0;
long long ans1=0;
long long ans2=0;
//容斥原理
for (int i=1;i<=n;i++)
{
ans1+=small1[i]; //合法a,b组
}
for (int i=1;i<=n;i++) //合法c,d组
{
ans2+=big1[i];
}
ans=ans1*ans2;
for (int i=1;i<=n;i++) //去掉有数相等的情况
{
ans-=small2[i]*big2[i];
ans-=small1[i]*small2[i];
ans-=big1[i]*big2[i];
ans-=small1[i]*big1[i];
}
cout << ans << endl;
}
int main()
{
//freopen("world.in","r",stdin);
//freopen("world.out","w",stdout);
while(~scanf("%d",&n))
{
solve();
}
return 0;
}