第一题:银行账户(account)
【题目描述】大家都知道28定律吧,据说世界上20%的人拥有80%的财富。现在你对一家银行的账户进行检测,看是否符合28定律,或者有更强的定律。比如说,10%的人拥有85%的财富。更准确的描述是:对N个银行账户进行调查,你的任务是找出两个数A,B,使得B-A的差最大。A,B的含义是A%的人拥有B%的财富。
【输入格式】
输入的第一行包含一个整数N(1<=N<=300000),表示银行账户的个数。
接下来一行包含N个整数,每个整数在区间[0,100000000],表示这N个账户中的存款金额。
【输出格式】
输出两行,分别是两个实数A,B。A,B的含义如题所述。误差在0.01内可以接受。
【输入样例】
2
100 200
【输出样例】
50.0
66.66666666666666
水题一道,就是注意
int
会爆就ok
直接上代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
const int MAXN=300000;
using namespace std;
struct node{double data;}ac[MAXN+5];
int n;
double temp,k,a1,a2;
long long sum;
bool cmp(node t1,node t2){return t1.data>t2.data;}
int main()
{
freopen("account.in","r",stdin);
freopen("account.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf",&ac[i].data);
sum+=ac[i].data;
}
sort(ac+1,ac+n+1,cmp);
for(int i=1;i<=n;i++)
{
k+=ac[i].data;
double t1=100*k/sum,t2=100.0*i/n;
if(temp<t1-t2)
{
a1=t1;
a2=t2;
temp=t1-t2;
}
else break;
}
printf("%lf",a2); putchar(10);
printf("%lf",a1); putchar(10);
}
第二题:染色面积(area)
【题目描述】给你N个矩形,这些矩形在平面坐标系中,并且以坐标系的零点为中心,它们的边都平行于坐标轴。每个矩形由宽度和高度可以唯一确定。现在对矩形进行染色操作。下图即是样例的示意图:
输入格式:
第一行包含1个整数N(1<=n<=1000000),表示矩形的个数。
接下来N行包含两个偶数X和Y(2<=X,Y<=10000000),分别表示宽度和高度。
输出格式:
一行,表示区域面积。
【输入样例】
3
8 2
4 4
2 6
【输出样例】
28
这道题也水,我旁边那位童鞋乍一看以为是矩形树,但仔细再想想就不对……
按y值从大到小排个序,也不用管什么这些矩形在平面坐标系中,并且以坐标系的零点为中心
就当他给的是一象限的x,y值
还有也是要注意int会爆,而且不只是答案,在计算答案的中间过程时也会爆(WA得我好爽)
主要思路是这样的:
按y值从大到小排序后,枚举y值
比较相邻的x值
设y值大者坐标为a(x1,y1),小者为b(x2,y2),S表示之前已覆盖的面积
显然y1 > y2
x分两种情况
(1) x1>=x2
显然b所覆盖的面积已被a覆盖,跳过这种情况即可
(2) x2>x1
此时,面积为:S+=(x2-x1)*y2;
代码如下:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
const int MAXN=1000000;
using namespace std;
struct POINT{int x,y;}point[MAXN+5];
int n,t;
unsigned long long ans;
bool cmp(POINT a,POINT b){return a.y>b.y;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&point[i].x,&point[i].y);
sort(point+1,point+n+1,cmp);
t=point[1].x; ans=point[1].x*point[1].y;
for(int i=2;i<=n;i++)
{
if(t<point[i].x)
{
ans+=(long long)((point[i].x-t))*point[i].y;
t=point[i].x;
}
}
printf("%I64d",ans);
}
对于接下来两道题,对于完全没搞懂的那道我会直接上标程和官方题解(标程我编译都会出毒,题解不知所云,有大神看懂了或知道怎么做还请指点下我)
第三题:航班(airline)
【题目描述】有N个城市,它们之间都有双向的航线。一个疯狂的航空公司老板经常改变航班日程。每天他都会做以下的事情:
1.选择一个城市
2.从该城市出发没有航线到达的城市全部开通航线,同时将之前开通的从该城市出发的所有航线全部取消
举个例子,比如从城市5出发,可以达到城市1和城市2,不能到达城市3和城市4,老板选择城市5做出改变后,那么城市5就有航班可以到达城市3和城市4,同时没有航班到达城市1和城市2了。
市民们想知道有没有一天,航线形成一个完全图。即每一个城市都有到达其他所有城市的航线,或者永远不可能形成一个完全图,不管老板如何操作。写一个程序来判断
【输入格式】
第一行包含一个整数N(2<=N<=1000),表示城市的数量。城市的编号从1到N
第二行包含一个整数M(0<=M<=N*(N-1)/2),表示当前航班的数量。
接下来又M行,每行包含两个不同的整数,A,B,表示A,B两个城市有航线。
【输出格式】
有且只有一行,如果能够形成完全图,则输出DA,如果不能形成完全图,则输出NE
【输入样例1】
2
0
【输出样例1】
DA
【输入样例2】
3
2
1 2
2 3
【输出样例2】
NE
【输入样例3】
4
2
1 3
2 4
【输出样例3】
DA
这道题有一个结论(不要问我怎么推的,猜了好多组数据+看了懵逼的题解总结出来的,如有错误很正常,也请指正)
就是如果能够形成完全图
当且仅当:
(1) 图中完全图数量不大于2
(2) 无边相连的点的个数不多于2
按着这思路写就莫名其妙的A了
代码如下:
#include<cstdio>
#include<algorithm>
const int MAXN=1000;
const int MAXM=500000;
using namespace std;
struct node{int e,next;}h[MAXM*2];
int Empty,Count,num,point,n,m,a,b,cnt,fir[MAXN+5];
bool used[MAXN+5][MAXN+5],vis[MAXN+5];
void dfs(int s){
vis[s]=1; point++;
for(int i=fir[s];i;i=h[i].next)
{
if(!used[s][h[i].e])
{
num++;
used[s][h[i].e]=1;
used[h[i].e][s]=1;
}
if(!vis[h[i].e]) dfs(h[i].e);
}
}
int main()
{
freopen("airline.in","r",stdin);
freopen("airline.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
h[++cnt].e=b;
h[cnt].next=fir[a];
fir[a]=cnt;
h[++cnt].e=a;
h[cnt].next=fir[b];
fir[b]=cnt;
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dfs(i);
if(point!=1) Count++;
else Empty++;
if(point*(point-1)/2!=num)
{
putchar('N'); putchar('E');
putchar(10);
return 0;
}
num=0; point=0;
}
}
if(Empty>2)
{
putchar('N'); putchar('E');
putchar(10);
}
else if(Count<=2)
{
putchar('D'); putchar('A');
putchar(10);
}
else
{
putchar('N'); putchar('E');
putchar(10);
}
}
第四题:数组询问(query)
【题目描述】Mirko是一个非常单纯的人,他的好朋友给他一个有N个自然数的数组,然后对他进行Q次查询.
每一次查询包含两个正整数L,R,表示一个数组中的一个区间[L,R],Mirko需要回答在这个区间中有多少个值刚好出现2次。
【输入格式】
第一行包含两个整数N和Q(1<=N,Q<=500000)
第二行包含N个自然数,这些数均小于1000000000,表示数组中的元素。
接下来有Q行,每行包含两个整数L和R(1<=L<=R<=N)。
【输出格式】
输出包含Q行,每行包含一次查询的答案。
【输入样例1】
5 1
1 2 1 1 1
1 3
【输出样例1】
1
【输入样例2】
5 2
1 1 1 1 1
2 4
2 3
【输出样例2】
0
1
下面那一道就是题解标程都看不懂的题了:
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long llint;
typedef pair <int, int> pii;
const int MAXN = 1 << 20;
int n, q;
vector <pii> T[MAXN];
int a[MAXN];
int ls[MAXN], rs[MAXN];
int left[MAXN];
int right[MAXN];
int ans[MAXN];
void update (int x, int l, int r, int L, int v) {
if (L > r || L < l) return;
T[x].push_back({rs[v], v});
int mid = (l + r) / 2;
if (l == r) return;
update(x * 2, l, mid, L, v);
update(x * 2 + 1, mid+1, r, L, v);
}
void query_update (int x, int l, int r, int L, int R, int p1, int p2) {
if (L > r || R < l) return;
if (l >= L && r <= R) {
T[x].push_back({p1, -1});
T[x].push_back({p2, -2});
return;
}
int mid = (l + r) / 2;
query_update(x * 2, l, mid, L, R, p1, p2);
query_update(x * 2 + 1, mid+1, r, L, R, p1, p2);
}
void solve (int x, int l, int r) {
sort(T[x].begin(), T[x].end());
int cnt = 0;
for (auto v: T[x]) {
if (v.second == -1) ++cnt;
else if (v.second == -2) --cnt;
else ans[v.second] += cnt;
}
if (l == r) return;
int mid = (l+r) / 2;
solve(x*2, l, mid);
solve(x*2+1, mid+1, r);
}
int main (void){
scanf("%d%d", &n, &q);
for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
for (int i = 0; i < q; ++i) {
scanf("%d%d", &ls[i], &rs[i]);
--ls[i]; --rs[i];
update(1, 0, n-1, ls[i], i);
}
map <int, int> M;
for (int i = 0; i < n; ++i) {
int pos = -1;
if (M.count(a[i])) pos = M[a[i]];
left[i] = pos;
M[a[i]] = i;
}
M.clear();
for (int i = n-1; i >= 0; --i) {
int pos = n;
if (M.count(a[i])) pos = M[a[i]];
right[i] = pos;
M[a[i]] = i;
}
right[n] = n;
for (int i = 0; i < n; ++i) {
int rpos = right[i];
if (rpos == n) continue;
query_update(1, 0, n-1, left[i] + 1, i, rpos, right[rpos]);
}
solve(1, 0, n-1);
for (int i = 0; i < q; ++i)
printf("%d\n", ans[i]);
return 0;
}
#include <string>
#include <vector>
#include <map>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long llint;
typedef pair <int, int> pii;
const int MAXN = 1 << 20;
int n, q;
vector <pii> T[MAXN];
int a[MAXN];
int ls[MAXN], rs[MAXN];
int left[MAXN];
int right[MAXN];
int ans[MAXN];
void update (int x, int l, int r, int L, int v) {
if (L > r || L < l) return;
T[x].push_back({rs[v], v});
int mid = (l + r) / 2;
if (l == r) return;
update(x * 2, l, mid, L, v);
update(x * 2 + 1, mid+1, r, L, v);
}
void query_update (int x, int l, int r, int L, int R, int p1, int p2) {
if (L > r || R < l) return;
if (l >= L && r <= R) {
T[x].push_back({p1, -1});
T[x].push_back({p2, -2});
return;
}
int mid = (l + r) / 2;
query_update(x * 2, l, mid, L, R, p1, p2);
query_update(x * 2 + 1, mid+1, r, L, R, p1, p2);
}
void solve (int x, int l, int r) {
sort(T[x].begin(), T[x].end());
int cnt = 0;
for (auto v: T[x]) {
if (v.second == -1) ++cnt;
else if (v.second == -2) --cnt;
else ans[v.second] += cnt;
}
if (l == r) return;
int mid = (l+r) / 2;
solve(x*2, l, mid);
solve(x*2+1, mid+1, r);
}
int main (void){
scanf("%d%d", &n, &q);
for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
for (int i = 0; i < q; ++i) {
scanf("%d%d", &ls[i], &rs[i]);
--ls[i]; --rs[i];
update(1, 0, n-1, ls[i], i);
}
map <int, int> M;
for (int i = 0; i < n; ++i) {
int pos = -1;
if (M.count(a[i])) pos = M[a[i]];
left[i] = pos;
M[a[i]] = i;
}
M.clear();
for (int i = n-1; i >= 0; --i) {
int pos = n;
if (M.count(a[i])) pos = M[a[i]];
right[i] = pos;
M[a[i]] = i;
}
right[n] = n;
for (int i = 0; i < n; ++i) {
int rpos = right[i];
if (rpos == n) continue;
query_update(1, 0, n-1, left[i] + 1, i, rpos, right[rpos]);
}
solve(1, 0, n-1);
for (int i = 0; i < q; ++i)
printf("%d\n", ans[i]);
return 0;
}