前几天把上次考试的题补得差不多了。差最后一题,貌似加上离散化后把原题写炸了,始终没有A掉。等集训一段时间在回头看这题吧。
正好暑期集训即将开始,感觉已经在家咸鱼了一个星期,再不做题怕是要爆零了。。。
------------------------------------------------------------------------------------------------------------------------------------------------------------
8月5日更新:最后一题已经AC了~,又干了3个小时。。。
-------------------------------------------------------------------------------------------------------------------------------------------------------------
A题(智能停车场)(xdoj1334)
模拟,可以按车辆到达时间排个序,然后对于每辆车,直接照车位就可以了。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
typedef struct
{
int s;
int e;
int ind;
int w;
} Car;
Car p[1010];
Car st[10100];
bool cmp1(Car x,Car y)
{
if(x.s!=y.s)
return x.s<y.s;
return x.ind<y.ind;
}
bool cmp2(Car x,Car y)
{
return x.ind<y.ind;
}
int a[1010];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&p[i].s,&p[i].e);
p[i].ind=i;
}
sort(p+1,p+n+1,cmp1);
st[0].e=100000;
for(int i=1;i<=n;i++)
{
int ind=i;
for(int j=1;j<=1000;j++)
{
if(p[i].s>=st[j].e)
{
ind=j;
break;
}
}
p[i].w=ind;
st[ind].e=p[i].e;
}
sort(p+1,p+n+1,cmp2);
printf("%d",p[1].w);
for(int i=2;i<=n;i++)
printf(" %d",p[i].w);
return 0;
}
B题(珂朵莉,威廉和第七兽)(xdoj1327)
直接暴搜,签到题。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
char maze[55][55];
int mp[55][55];
int vis[55][55];
int c1,c2,c3,c4=0;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
int n,m;
void dfs(int x,int y,int num)
{
for(int i=0;i<=4;i++)
{
int tx=x+dx[i];
int ty=y+dy[i];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[tx][ty]==num&&!vis[tx][ty])
{
vis[tx][ty]=1;
dfs(tx,ty,num);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
getchar();
for(int i=1;i<=n;i++)
{
scanf("%s",maze[i]);
getchar();
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<m;j++)
{
if(maze[i][j]=='A')
{
mp[i][j+1]=1;
}
else if(maze[i][j]=='B')
{
mp[i][j+1]=2;
}
else if(maze[i][j]=='C')
{
mp[i][j+1]=3;
}
else if(maze[i][j]=='D')
{
mp[i][j+1]=4;
}
}
}
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// printf("%d",mp[i][j]);
// printf("\n");
// }
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]==1&&!vis[i][j])
{
dfs(i,j,1);
c1++;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]==2&&!vis[i][j])
{
dfs(i,j,2);
c2++;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]==3&&!vis[i][j])
{
dfs(i,j,3);
c3++;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]==4&&!vis[i][j])
{
dfs(i,j,4);
c4++;
}
}
}
printf("%d %d %d %d",c1,c2,c3,c4);
return 0;
}
C题(拿石头的游戏)(xdoj1328)
白书上模板题-硬币游戏
相信学过博弈论后大家对这道题有了刚深入的理解。。。
代码:
#include<bits/stdc++.h>
using namespace std;
int X,K,A[110];
bool win[10010];
void solve()
{
win[0]=false;
for(int j=1;j<=X;j++)
{
win[j]=false;
for(int i=0;i<K;i++)
{
win[j] |= A[i] <=j&&!win[j-A[i]];
}
}
if(win[X])
{
puts("tsy");
}
else
puts("zxy");
}
int main()
{
while(scanf("%d%d",&X,&K)!=EOF)
{
for(int i=0;i<K;i++)
scanf("%d",&A[i]);
solve();
}
return 0;
}
D题(忙碌的周末)(xdoj1333)
CF上原题,这道题关键在于推出这个集合中最多有三个数,分类讨论即可
代码(写的有点丑):
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
ll a[200010];
ll pre[100];
map<ll,ll> mp;
int main()
{
int n;
int f=0;
pre[0]=1;
for(int i=0;i<=33;i++)
{
pre[i+1]=2*pre[i];
}
while(scanf("%d",&n)!=EOF)
{
f=0;
ll c[3];
mp.clear();
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
mp[a[i]]++;
}
sort(a+1,a+1+n);
int cnt;
for(int i=1;i<=n;i++)
{
int u=0;
c[u++]=a[i];
cnt=0;
for(int j=0;j<=34;j++)
{
if(mp[a[i]+pre[j]]!=0&&mp[a[i]+2*pre[j]]!=0)
{
c[1]=a[i]+pre[j];
c[2]=a[i]+2*pre[j];
cnt=2;
}
if(cnt==2)
{
printf("3\n");
printf("%lld %lld %lld\n",c[0],c[1],c[2]);
f=1;
break;
}
}
if(f==1)
{
break;
}
}
if(f==0)
{
for(int i=1;i<=n;i++)
{
int u=0;
c[u++]=a[i];
cnt=0;
for(int j=0;j<=34;j++)
{
if(mp[a[i]+pre[j]]!=0)
{
c[u++]=a[i]+pre[j];
cnt++;
}
if(cnt==1)
{
printf("2\n");
printf("%lld %lld\n",c[0],c[1]);
f=1;
break;
}
}
if(f==1)
break;
}
}
if(f==0)
{
printf("1\n");
printf("%lld\n",a[1]);
}
}
return 0;
}
E题( 珂朵莉、威廉和第十一兽 )
这道题直接bfs即可,不过需要注意一些特殊情况,特判一下。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
typedef struct
{
int x;
int y;
int c;
int s;
} P;
int mp[110][110];
int vis[110][110];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
char mmp[110][110];
int n,m,t,tx,ty,fx,fy;
int bfs()
{
queue<P> q;
P t1;
t1.c=mp[fx][fy];
t1.s=0;
t1.x=fx;
t1.y=fy;
q.push(t1);
while(!q.empty())
{
P tt=q.front();
q.pop();
if(tt.x==tx&&tt.y==ty)
return tt.s;
for(int i=0;i<4;i++)
{
int nx=tt.x+dx[i];
int ny=tt.y+dy[i];
int pan=(tt.c+1)%t;
if(pan==0)
pan=t;
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&mp[nx][ny]==pan&&!vis[nx][ny])
{
P t2;
vis[nx][ny]=1;
t2.x=nx;
t2.y=ny;
t2.c=mp[nx][ny];
t2.s=tt.s+1;
q.push(t2);
}
}
}
return -1;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&t)!=EOF)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
scanf("%s",mmp[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<m;j++)
{
mp[i][j+1]=mmp[i][j]-'0';
}
}
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// printf("%d",mp[i][j]);
// printf("\n");
// }
scanf("%d%d%d%d",&fx,&fy,&tx,&ty);
if(t==0)
{
printf("-1\n");
continue;
}
if(!fx||!fy||!tx||!ty)
{
printf("-1\n");
continue;
}
int res=bfs();
if(res==-1)
printf("-1\n");
else
printf("%d\n",res);
}
return 0;
}
F题(生命仪式)(xdoj1326)
区间dp,可参考NOIP原题-能量项链,套路是一样的。不过为什么用之前软院新生赛的标程会T掉呢?(滑稽)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[810][810];
ll a[810];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
a[n+i]=a[i];
}
for(int j=2;j<=2*n;j++)
{
for(int i=j-1;i>0&&j-i<n;i--)
{
for(int k=i;k<j;k++)
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[i]*a[j+1]*a[k+1]);
}
}
ll ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,dp[i][i+n-1]);
printf("%lld\n",ans);
}
return 0;
}
G题(上海上海上海上海蓬莱蓬莱蓬莱蓬莱 ) (xdoj1329)
听之前想了很长时间也不会,听后秒懂系列。
把B当成-1,把R当成1,维护前缀和,再O(n)扫描一遍即可。
代码:
#include<bits/stdc++.h>
using namespace std;
char s[1100000];
int a[1100000];
int sum[1100000];
int rec[1100000];
int flag[1100000];
int main()
{
while(scanf("%s",s)!=EOF)
{
int len=strlen(s);
memset(rec,0,sizeof(rec));
memset(flag,0,sizeof(flag));
for(int i=0;i<len;i++)
{
if(s[i]=='R')
{
a[i+1]=1;
}
else
a[i+1]=-1;
}
sum[0]=0;
rec[0]=0;
flag[0]=1;
for(int i=1;i<=len;i++)
{
sum[i]=sum[i-1]+a[i];
if(!flag[sum[i]])
{
flag[sum[i]]=1;
rec[sum[i]]=i;
}
}
int ans=0;
for(int i=1;i<=len;i++)
{
if(flag[sum[i]]!=0)
{
ans=max(i-rec[sum[i]],ans);
}
}
printf("%d\n",ans);
}
return 0;
}
H题(天才琪露诺的完美算数教室 ) (xdoj1330)
打表异或前缀和找规律,这里直接用的题解的思路了,又特判一下0,1,2。不过这道题感觉还没有完全弄懂的样子。。。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll t,n;
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
if(n==0)
{
printf("4 7\n");
}
else if(n==1)
{
printf("1 5\n");
}
else if(n==2)
{
printf("3 5\n");
}
else
{
if(n%4==0)
{
printf("%d %lld\n",1,n);
}
else if(n%4==1)
{
printf("%d %lld\n",2,n-1);
}
else if(n%4==2)
{
printf("%d %lld\n",2,n);
}
else
{
printf("%d %lld\n",1,n-1);
}
}
}
return 0;
}
I题(区间第K大)(xdoj1336)
最开始想写二分+BIT,T掉了,而且也有些复杂。后来发现这道题满足区间递增性,用二分加尺取,直接过了。
大致思路就是每次二分时看比这个区间严格大的有多少个,如果这个数比K小就更新答案,不断逼近答案,最后得出解。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll tem[100005];
ll sum[100005];
int n,k;
ll cal(ll mid)
{
int r=1;
ll res=0;
for(int i=0;i<n;i++)
{
while(r<=n&&sum[r]-sum[i]<=mid)
r++;
if(sum[r]-sum[i]<=mid)
break;
res+=(n-r+1);
}
return res;
}
int main()
{
int i,j;
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%lld",&tem[i]);
scanf("%d",&k);
for (i=1;i<=n;i++)
{
sum[i]=sum[i-1]+tem[i];
}
ll maxx=1e14+10;
ll minn=0;
ll l=minn,r=maxx;
ll ans=0;
while(l<=r)
{
ll mid=(l+r)>>1;
if (cal(mid)>=k)
l=mid+1;
else
{
r=mid-1;
ans=mid;
}
}
printf("%lld\n",ans);
return 0;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------
J题 火聚聚铺地毯(xdoj1324)
这道题可以说是poj3171和poj2528的一个结合版,难度加大了不少,在上次比赛中出现在最后一题的位置(不过有几位聚聚做出来了,膜)。首先总体上dp的思路是好想的,可以设dp[i]为到 i 位置的最小花费,易得dp[i]=min(dp[j])+c[i].w;(a[i].l-1<=j<=a[i].r)。可是这么算复杂度是O(n^2),要超时的。因为是区间查询最值问题,想到线段树。用Minv数组维护dp数组,每次查询之前区间的最小值为log(sum),sum为地毯总长度,不过这道题sum过大,线段树存不下,考虑离散化。这道题还需要考虑相邻两个点之间离散化后若相邻,需判断原来两个点是否直接相邻,若不,再中间加一个点(详见代码)。此时sum最高为400000左右,总复杂度nlog(sum), 刚刚好。
代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
typedef long long ll;
const int maxn = 400010;
int Min[maxn<<2];
void PushUP(int rt) {
Min[rt] = min(Min[rt<<1] , Min[rt<<1|1]);
}
typedef struct
{
ll li;
ll ri;
int w;
} Cloth;
Cloth c[100010];
Cloth ccopy[100010];
ll lisan[400040];
bool cmp(Cloth x,Cloth y)
{
if(x.li!=y.li)
return x.li<y.li;
return x.ri<y.ri;
}
void build(int l,int r,int rt) {
Min[rt]=2e9;
if(l == r)
return ;
int m = (l + r) >> 1;
build(lson);
build(rson);
}
void update(int p,int sc,int l,int r,int rt) {
if (l == r) {
Min[rt] = min(Min[rt],sc);
return ;
}
int m = (l + r) >> 1;
if (p <= m) update(p , sc , lson);
else update(p , sc , rson);
PushUP(rt);
}
int query(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R) {
return Min[rt];
}
int m = (l + r) >> 1;
int ret = 2e9;
if (L <= m) ret = min(ret , query(L , R , lson));
if (R > m) ret = min(ret , query(L , R , rson));
return ret;
}
int main()
{
int n;
ll m,e;
scanf("%d%lld%lld",&n,&m,&e);
for(int i=0;i<n;i++)
{
scanf("%lld%lld%d",&c[i].li,&c[i].ri,&c[i].w);
ccopy[i].li=c[i].li;
ccopy[i].ri=c[i].ri;
}
int tot=0;
for(int i=0;i<n;i++)
{
lisan[tot++]=c[i].li;
lisan[tot++]=c[i].ri;
}
lisan[tot++]=m;
lisan[tot++]=e;
sort(lisan,lisan+tot);
int num=unique(lisan,lisan+tot)-lisan;
int tt=num;
for(int i=1;i<=tt;i++)
{
if(lisan[i]-lisan[i-1]>1)
{
lisan[num++]=lisan[i-1]+1;
}
}
sort(lisan,lisan+num);
ll mm = lower_bound(lisan,lisan+num,m)-lisan;
mm++;
ll ee = lower_bound(lisan,lisan+num,e)-lisan;
ee++;
for(int i=0;i<n;i++)
{
c[i].li=lower_bound(lisan,lisan+num,c[i].li)-lisan;
c[i].ri=lower_bound(lisan,lisan+num,c[i].ri)-lisan;
c[i].li++;
c[i].ri++;
}
sort(c,c+n,cmp);
sort(ccopy,ccopy+n,cmp);
build(mm-1,ee,1);
ll cur=mm-1;
update(cur,0,mm-1,ee,1);
cur = m-1;
int flag=1;
for(int i=0;i<n;i++)
{
if(ccopy[i].li>cur+1)
{
flag=0;
break;
}
int tem=query(c[i].li-1,c[i].ri,mm-1,ee,1);
update(c[i].ri,tem+c[i].w,mm-1,ee,1);
cur=max(cur,ccopy[i].ri);
}
if(e > cur)
{
printf("-1\n");
return 0;
}
if(flag)
printf("%d\n",query(ee,ee,mm-1,ee,1));
else
printf("-1\n");
return 0;
}