这次有点萎,本来第三题可以95分的,结果数组开小了,只得了65分。
60+60+65=185。
第一题奇奇怪怪地我竟然没有想到方法。
T1: 【NOIP2013模拟联考11】剑与魔法(dragons)
首先我们记录下所有点之前最多可以取的数量。
然后就用一个堆(小根堆),每次如果放的进去就放,放不进去就直接看看可不可以替换堆顶。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n;
int a[200010];
int x[200010];
int kind[200010];
int d[200010];
void up(int x)
{
while((x>>1)>0&&d[x]<d[x>>1])
{
swap(d[x],d[x>>1]);
x=x>>1;
}
}
void down(int x)
{
int k;
while(((x<<1)<=d[0]&&d[x]>d[x<<1])||((x<<1)+1<=d[0]&&d[x]>d[(x<<1)+1]))
{
k=x<<1;
if(k+1<=d[0]&&d[k+1]<d[k])++k;
swap(d[x],d[k]);
x=k;
}
}
int main()
{
scanf("%d\n",&n);
int i;
char k;
for (i=1;i<=n;++i)
{
scanf("%c%d\n",&k,&x[i]);
if(k=='c') kind[i]=0;
if(k=='e') kind[i]=1;
}
int ans=2147483647;
for (i=n-1;i>=1;--i)
if(kind[i]==0) a[i]=ans;
else ans=min(ans,x[i]-1);
for (i=1;i<=n;++i)
if(kind[i]==0)
{
if(d[0]<a[i])
{
d[++d[0]]=x[i];
up(d[0]);
}
else
{
if(d[1]<x[i])
{
d[1]=x[i];
down(1);
}
}
}
long long sum=0;
for (i=1;i<=d[0];++i) sum+=d[i];
printf("%lld\n",sum);
}
T2: 【NOIP2013模拟联考11】矩形(rect)
30%直接暴力4重。
60%把每次枚举的两条线变成一条,然后结束后用组合数计算。3重。
100%把每次枚举的那一条线预处理出来,然后判断我们枚举的两条线的交集。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,ans,sum;
int par[2010],ver[2010];
int par2[2010][2010];
bool bz[2010][2010];
int main()
{
scanf("%d",&n);
int i,j,k,l,x1[2010],y1[2010],x2[2010],y2[2010];
for (i=1;i<=n;++i)
{
scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]);
if(x1[i]==x2[i]) par[++par[0]]=i;
else ver[++ver[0]]=i;
}
memset(bz,0,sizeof(bz));
for (i=1;i<=par[0];++i)
for (j=1;j<=ver[0];++j)
if(min(x1[ver[j]],x2[ver[j]])<=x1[par[i]]&&max(x1[ver[j]],x2[ver[j]])>=x1[par[i]]&&min(y1[par[i]],y2[par[i]])<=y1[ver[j]]&&max(y1[par[i]],y2[par[i]])>=y1[ver[j]])
{
par2[i][++par2[i][0]]=j;
bz[i][j]=true;
}
for (i=1;i<=par[0]-1;++i)
for (j=i+1;j<=par[0];++j)
{
sum=0;
for (k=1;k<=par2[i][0];++k)
if(bz[j][par2[i][k]])++sum;
ans=ans+(sum*(sum-1))/2;
}
printf("%d\n",ans);
}
T3:【NOIP2013模拟11.4A组】善良的精灵(fairy)
我们可以把这题转化成两个方法:
①二分图染色(暴力)时间复杂度
O
(
m
2
)
O(m^2)
O(m2)
②差分约束,时间复杂度
O
(
m
)
O(m)
O(m)
在这里就只讲差分约束了。
首先我们把这个图看成一个树,然后有环的时候就把它连成一条反阻边,然后按照差分约束的原理,我们就可以在当前的地方打一个+1表示,然后在反阻边另一端的点上打一个-1,然后在从底向头找,就好了。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int next[20010],last[20010],tov[20010],num[20010];
int n,m,tot;
bool flag;
int f1[20010],f2[20010],g1[20010],g2[20010];
bool bz[20010],bz1[20010];
int deep[10010];
int ans[10010];
void insert(int x,int y,int i)
{
tov[++tot]=y;
num[tot]=i;
next[tot]=last[x];
last[x]=tot;
}
void dfs(int t,int fa)
{
int i=last[t];
int y;
deep[t]=deep[fa]+1;
while(i)
{
y=tov[i];
if(y==fa)
{
i=next[i];
continue;
}
if(deep[y]==0)
{
bz[i]=1;
dfs(y,t);
}
else
if(deep[y]<deep[t])
{
if((deep[t]-deep[y]+1)%2)
{
++tot;
g1[t]+=1;
g1[y]-=1;
f1[num[i]]=1;
}
else
{
g2[t]+=1;
g2[y]-=1;
f2[num[i]]=1;
}
i=next[i];
continue;
}
i=next[i];
}
}
void find(int x)
{
bz1[x]=true;
int i=last[x];
while (i!=0)
{
if (bz[i])
{
find(tov[i]);
f1[num[i]]=g1[tov[i]];
f2[num[i]]=g2[tov[i]];
g1[x]=g1[x]+g1[tov[i]];
g2[x]=g2[x]+g2[tov[i]];
}
i=next[i];
}
}
int main()
{
freopen("fairy.in","r",stdin);
freopen("fairy.out","w",stdout);
scanf("%d%d",&n,&m);
int i,j,x,y;
for (i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
insert(x,y,i);
insert(y,x,i);
}
tot=0;
deep[1]=1;
memset(deep,0,sizeof(deep));
for(i=1;i<=n;i++)
if(!deep[i]) dfs(i,0);
if(tot==0)
{
printf("%d\n",m);
for (i=1;i<=m;++i)
printf("%d ",i);
}
else
{
for (i=1;i<=n;++i)
if(!bz1[i]) find(i);
for (i=1;i<=m;++i)
if(f1[i]==tot&&f2[i]==0)
ans[++ans[0]]=i;
printf("%d\n",ans[0]);
for (i=1;i<=ans[0];++i)
printf("%d ",ans[i]);
}
}