目录
前言
本场考试被同学们(一群大佬!except me!)称为“基础测验”,前4~5道题基本ac(except me!)
所以在大家正欢乐地研究第六道题时,我默默地补起了题并打开了CSDN... ...
总结一下,有两点:
1.自己思路太清奇,没想清楚,有点“赌一把”的心态
2.基础不好,有待提升,要多刷题并及时写博客督促自己搞懂
题目解析
一、Tuna
题目
Sample Input 1
5 2
3 4
2 1
5 3
4 4
4 2Sample Output 1
19
Sample Input 2
4
2
3 5
2 8
4
6 5
6 3
7Sample Output 2
22
Sample Input 3
3
10
20 50
30
20 40
50
70 20
10Sample Output 3
90
分析
如果p1,p2差值小于等于x,答案就加较大值
否则输入并加入p3
(差点想复杂了,以为会有abs(p1-p2)<=x且输入了p3的情况)
代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,x,cnt,p1,p2,p3;
int main()
{
//freopen("tuna.in","r",stdin);
//freopen("tuna.out","w",stdout);
scanf("%d%d",&n,&x);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&p1,&p2);
if(abs(p1-p2)<=x)
cnt+=max(p1,p2);
else
{
scanf("%d",&p3);
cnt+=p3;
}
}
printf("%d\n",cnt);
return 0;
}
二、Pareto
题目
Sample Input 1
2
100 200Sample Output 1
50.0
66.66666666666666
Sample Input 2
8
100100 10 100 1000 1 10100 90100
100100Sample Output 2
37.5
96.28172769816027
分析
自己的思路:类似贪心
设选择的客户数为x,所选客户数的总金额为xc
A% = x / n;B% = xc / tot
n,tot为定值,要B%-A%最大,就要xc尽可能大,x尽可能小
先把c[ ]从大到小排序,每次加入一个客户,如果差值变小就存下加之前的答案然后结束
——>因为c[ i ]是递减,若现在的c[ i ]加上后差值变小,则后面的c[ j ]无论如何也不会比当前c[ i ]更优,也就不会使差值变大了,因此可以直接结束
测完没想到这个思路只对了1/4的点,反思半天也没想出来,
最后发现居然是没开long long的锅(自己的思路没问题,开心)
正解思路:其实也是贪心...
和自己想的差不多,只是如果加入一个客户后,差值变大就更新答案,不管怎样仍然继续循环
AC代码-Myself
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=3e5;
ll c[MAXN+5];
ll n,tot,xc;
double tmp1,tmp2,Max=-10*1.0;
bool cmp(ll a,ll b)
{
return a>b;
}
int main()
{
//freopen("pareto.in","r",stdin);
//freopen("pareto.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&c[i]);
tot+=c[i];
}
sort(c+1,c+n+1,cmp);
for(int i=1;i<=n;i++)
{
xc+=c[i];
tmp1=(double)xc/tot;
tmp2=(double)i/n;
if(tmp1-tmp2>Max)
Max=tmp1-tmp2;
else
{
tmp1=(double)(xc-c[i])/tot;
tmp2=(double)(i-1)/n;
printf("%.3f\n%.10f\n",tmp2*100,tmp1*100);
return 0;
}
}
printf("%.3f\n%.10f\n",tmp2*100,tmp1*100);
return 0;
}
AC代码-std版
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=3e5;
ll c[MAXN+5];
ll n,tot,xc;
double tmp1,tmp2,ans1,ans2,Max=-10*1.0;
bool cmp(ll a,ll b)
{
return a>b;
}
int main()
{
//freopen("pareto.in","r",stdin);
//freopen("pareto.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&c[i]);
tot+=c[i];
}
sort(c+1,c+n+1,cmp);
for(int i=1;i<=n;i++)
{
xc+=c[i];
tmp1=xc*100.0/tot;
tmp2=i*100.0/n;
if(tmp1-tmp2>Max)
{
Max=tmp1-tmp2;
ans1=tmp1;
ans2=tmp2;
}
}
printf("%.3f\n%.3f\n",ans2,ans1);
return 0;
}
三、Unija
题目
Sample Input 1
3
8 2
4 4
2 6Sample Output 1
28
Sample Input 2
5
2 10
4 4
2 2
8 8
6 6Sample Output 2
68
分析
考试时自己想到了把x或y排序,但是捣鼓半天没捣鼓对...果然能力还是不足...
改后思路:
因为矩形的中心在原点,图形为上下左右对称图形...所以可以把图形简化:只研究它的1/4
把各矩形按高度从大到小排序,从左至右扫一遍(扫描过程为红色的线“ fx ”)即可计算答案
若当前矩形为图中有深蓝色边框的,上一次处理后fx的位置大于(或等于)当前矩形的x则跳过
考试瞎搞导致WA-代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=(int)1e6;
int n,ans,add,max_y,tmp,flag;
struct node
{
int x,y;
}a[MAXN+5];
bool cmp(node a,node b)
{
if(a.x<=b.x&&a.y>=b.y)
return true;
if(a.x<=b.x)
return true;
else
return false;
}
int main()
{
//freopen("unija.in","r",stdin);
//freopen("unija.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
a[i].x/=2;
a[i].y/=2;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
tmp=0,flag=0;
//printf("x:%d y:%d\n",a[i].x,a[i].y);
if(a[i].y>=a[i-1].y)
{
for(int j=1;j<=i-1;j++)
{
if(a[j].y>a[i].y)
{
tmp+=a[j].x*(a[j].y-a[i].y);
flag=1;
}
else
break;
}
add=a[i].x*a[i].y-ans+tmp;
}
//add=a[i].x*a[i].y-a[i-1].x*a[i-1].y;
else
add=(a[i].x-a[i-1].x)*a[i].y;
ans+=add;
//printf("tmp:%d\n",tmp);
//printf("*%d %d\n",ans,add);
}
printf("%d\n",ans*4);
return 0;
}
AC代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=(int)1e6;
ll n,ans,s,max_y=-1,max_x=-1,tmp,flag,fx;
struct node
{
ll x,y;
}a[MAXN+5];
bool cmp(const node &a,const node &b)
{
return a.y>b.y;
}
int main()
{
//freopen("unija.in","r",stdin);
//freopen("unija.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
a[i].x/=2;
a[i].y/=2;
max_x=max(max_x,a[i].x);
max_y=max(max_y,a[i].y);
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
if(a[i].x<=fx)
continue;
s+=1LL*a[i].y*(a[i].x-fx);
fx=a[i].x;
}
printf("%I64d\n",s*4LL);
return 0;
}
四、Ronald
题目
Sample Input 1
2
0
Sample Output 1
DA
Sample Input 2
3
2
1 2
2 3
Sample Output 2
NE
Sample Input 3
4
2
1 3
2 4
Sample Output 3
DA
分析
对于一条边“A—B”,对A或对B的操作次数都会改变该边的状态(有/没有),则该边的状态取决于A和B的操作次数是否相同
考虑到这一点,就假设每个点操作0次或1次(操作或不操作)即可,简化了任务
从顶点(1号点)开始,
(1)假设顶点先不操作,再确定其他点“K”是否操作,来保证存在边“1—K”,操作完后检查图中的点是否两两相连
(2)假设顶点操作,再重复(1)的方法
代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1000;
int a[MAXN+5][MAXN+5],b[MAXN+5][MAXN+5];
int n,m,u,v;
void Change(int a[MAXN+5][MAXN+5],int x)
{//去掉与x相连的边,加上不相连的边
for(int i=1;i<=n;i++)
//可以直接写: a[x][i]=a[i][x]=1-a[i][x];
if(a[x][i]==0)
a[x][i]=a[i][x]=1;
else
a[x][i]=a[i][x]=0;
}
bool Check(int a[MAXN+5][MAXN+5])
{
//将与顶点不相连的边变成相连
for(int i=2;i<=n;i++)
if(!a[i][1])
Change(a,i);
//检查图中各点是否两两相连:
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(a[i][j]==0)
return false;
return true;
}
int main()
{
//freopen("ronald.in","r",stdin);
//freopen("ronald.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
a[u][v]=a[v][u]=1;
b[u][v]=b[v][u]=1;
}
if(Check(a))
{
printf("DA\n");
return 0;
}
Change(b,1);//改变一次顶点的连接状态,再检查一次
if(Check(b))
{
printf("DA\n");
return 0;
}
else
printf("NE\n");
return 0;
}
五、Poklon
题目
Sample Input 1
5 1
1 2 1 1 1
1 3
Sample Output 1
1
Sample Input 2
5 2
1 1 1 1 1
2 4
2 3
Sample Output 2
0
1
Sample Input 3
5 2
1 1 2 2 3
1 1
1 5
Sample Output 3
0
2
分析
首先恭喜自己考试中第三次MLE!
因为自己还没开始学写“莫队”算法(老师布置了题,但是我莫得时间),所以考试的时候不会打,只能瞎搞qwq...
接下来说正事...
看题目和数据范围可以确定方法:法一:莫队,法二:线段树
这里用的莫队模板
Ps.数据太大,要离散化(见函数Prepare( ))
MLE-考试瞎搞-代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=5e5,MAXT=1e8;
int a[MAXN+5],vis[MAXT+5],cnt[MAXT+5];
int n,q,l,r,ans;
int main()
{
//freopen("poklon.in","r",stdin);
//freopen("poklon.out","w",stdout);
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
while(q--)
{
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
ans=0;
scanf("%d%d",&l,&r);
for(int i=l;i<=r;i++)
cnt[a[i]]++;
for(int i=l;i<=r;i++)
{
if(cnt[a[i]]==2&&!vis[a[i]])
{
vis[a[i]]=1;
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}
AC代码
特别鸣谢:CXH
#include<cstdio>
#include<map>
#include<vector>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=5e5,MAXT=1e8;
int a[MAXN+5],cnt[MAXN+5],ans[MAXN+5];
int n,m,res,K;
struct node
{
int l,r,id;
}q[MAXN+5];
bool cmp(node a,node b)
{
int x=(a.l+K-1)/K,y=(b.l+K-1)/K;
if(x==y)
return a.r<b.r;
return x<y;
}
void Prepare()//将数组a离散化
{
map<int,bool> vis;
map<int,int> rank;
vector<int> g;
for(int i=1;i<=n;i++)
if(!vis[a[i]])
{
g.push_back(a[i]);
vis[a[i]]=1;
}
sort(g.begin(),g.end());
for(int i=0;i<g.size();i++)
rank[g[i]]=i+1;
for(int i=1;i<=n;i++)
a[i]=rank[a[i]];
}
void Remove(int x)
{
cnt[a[x]]--;
if(cnt[a[x]]==1)
res--;
if(cnt[a[x]]==2)
res++;
}
void Add(int x)
{
cnt[a[x]]++;
if(cnt[a[x]]==3)
res--;
if(cnt[a[x]]==2)
res++;
}
int main()
{
//freopen("poklon.in","r",stdin);
//freopen("poklon.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
K=sqrt(n);
Prepare();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int dl=0,dr=0;
for(int i=1;i<=m;i++)
{
int L=q[i].l,R=q[i].r;
while(dl<L)
Remove(dl++);
while(dr>R)
Remove(dr--);
while(dl>L)
Add(--dl);
while(dr<R)
Add(++dr);
ans[q[i].id]=res;
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}