今天的模拟赛打完就可以开始颓到NOIP2018前一个小时了...
T1:
题目大意:给你一个五子棋的下棋序列,让你判定在什么时候结束,谁赢了.
考场得分:100.
每一次处理的时候判定一下就可以了十分容易.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=15;
int a[N+9][N+9],n;
bool check(int x,int y){ //判定是否决出胜负
int sum=1;
for (int i=x-1;a[i][y]==a[x][y];--i) ++sum;
for (int i=x+1;a[i][y]==a[x][y];++i) ++sum;
if (sum>=5) return 1;
//行
sum=1;
for (int j=y-1;a[x][j]==a[x][y];--j) ++sum;
for (int j=y+1;a[x][j]==a[x][y];++j) ++sum;
if (sum>=5) return 1;
//列
sum=1;
for (int i=x-1,j=y-1;a[i][j]==a[x][y];--i,--j) ++sum;
for (int i=x+1,j=y+1;a[i][j]==a[x][y];++i,++j) ++sum;
if (sum>=5) return 1;
//x-y相等的对角线
sum=1;
for (int i=x-1,j=y+1;a[i][j]==a[x][y];--i,++j) ++sum;
for (int i=x+1,j=y-1;a[i][j]==a[x][y];++i,--j) ++sum;
if (sum>=5) return 1;
//x+y相等的对角线
return 0;
}
Abigail getans(){
scanf("%d",&n);
int x,y;
for (int i=1;i<=n;++i){
scanf("%d%d",&x,&y);
a[x][y]=i&1?1:2;
if (check(x,y)){
i&1?printf("A %d\n",i):printf("B %d\n",i);
break;
}
x=y=0;
}
if (!x) puts("Tie");
}
int main(){
freopen("five.in","r",stdin);
freopen("five.out","w",stdout);
getans();
return 0;
}
T2:
题目大意:给定一张无向图,以及k个终点.现在要从点0走到这k个终点,且在当前点会有随机的d条以当前点为一端的边不能走,求在最坏情况下的最短路.
考场得分:75.
考场看到这道图论题就感觉比较容易,应该可以拿个高分,然后开始磕.先考虑了若是DAG上的情况,发现从终点开始反着DP即可.然后考虑无向图上,就把DP换成最短路就可以开心的AC这道题了.
然后发现这道题直接写堆优化dijkstra貌似是错误的,貌似必须要用SPFA的多次迭代才能完成,然后就写了一个时间复杂度上限但实际跑得飞快的SPFA,拿到了75分的高分.
实际上正解是一个被魔改了的dijkstra.我们考虑这道题与普通最短路的区别,发现只是多了一个取d+1短的条件.那么考虑给每一个点维护一个大小不超过d+1的大根堆,存所有dis值已经确定的与这个点相邻的dis值,那么每次更新一个值取堆顶即可.
75分SPFA代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000,M=1000000;
const LL INF=(1LL<<60)-1;
struct side{
int y,next;
LL v;
}e[M*2+9];
int lin[N+9],top=1;
int fr[N+9],k,n,m,d;
void ins(int x,int y,LL v){
e[++top].y=y;e[top].v=v;
e[top].next=lin[x];
lin[x]=top;
}
int use[N+9],tt;
LL dis[N+9],tmp[N+9];
queue<int>q;
void SPFA(){
for (int i=1;i<=n;++i) dis[i]=INF;
for (int i=1;i<=k;++i){
dis[fr[i]]=0;
use[fr[i]]=1;
q.push(fr[i]);
}
while (!q.empty()){
int t=q.front();q.pop();
use[t]=0;
for (int i=lin[t];i;i=e[i].next){
tt=0;
for (int j=lin[e[i].y];j;j=e[j].next)
tmp[++tt]=dis[e[j].y]+e[j].v;
if (d>=tt) continue;
nth_element(tmp+1,tmp+d+1,tmp+tt+1);
if (tmp[d+1]<dis[e[i].y]){
dis[e[i].y]=tmp[d+1];
if (use[e[i].y]) continue;
use[e[i].y]=1;
q.push(e[i].y);
}
}
}
}
Abigail into(){
scanf("%d%d%d%d",&n,&m,&k,&d);
int x,y;LL v;
for (int i=1;i<=m;++i){
scanf("%d%d%lld",&x,&y,&v);
++x;++y;
ins(x,y,v);ins(y,x,v);
}
for (int i=1;i<=k;++i) {
scanf("%d",&fr[i]);
++fr[i];
}
}
Abigail work(){
SPFA();
}
Abigail outo(){
printf("%lld\n",dis[1]==INF?-1:dis[1]);
}
int main(){
freopen("maze.in","r",stdin);
freopen("maze.out","w",stdout);
into();
work();
outo();
return 0;
}
100分堆优化dijkstra代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000,M=1000000;
const LL INF=(1LL<<60)-1;
struct side{
int y,next;
LL v;
}e[M*2+9];
int lin[N+9],top=1;
int fr[N+9],k,n,m,D;
void ins(int x,int y,LL v){
e[++top].y=y;e[top].v=v;
e[top].next=lin[x];
lin[x]=top;
}
int use[N+9];
LL dis[N+9];
struct node{
int x;
LL v;
node(){}
node(int X,int V){x=X;v=V;}
bool operator > (const node &p)const{return v>p.v;}
};
priority_queue<node,vector<node>,greater<node> >q;
priority_queue<LL>d[N+9];
void dijkstra(){
for (int i=1;i<=n;++i) dis[i]=INF;
for (int i=1;i<=k;++i){
dis[fr[i]]=0;
q.push(node(fr[i],0LL));
}
while (!q.empty()){
int t=q.top().x;q.pop();
if (use[t]) continue;
use[t]=1;
for (int i=lin[t];i;i=e[i].next){
d[e[i].y].push(dis[t]+e[i].v);
if (d[e[i].y].size()>D+1) d[e[i].y].pop();
if (d[e[i].y].size()==D+1&&d[e[i].y].top()<dis[e[i].y]){
dis[e[i].y]=d[e[i].y].top();
q.push(node(e[i].y,dis[e[i].y]));
}
}
}
}
Abigail into(){
scanf("%d%d%d%d",&n,&m,&k,&D);
int x,y;LL v;
for (int i=1;i<=m;++i){
scanf("%d%d%lld",&x,&y,&v);
++x;++y;
ins(x,y,v);ins(y,x,v);
}
for (int i=1;i<=k;++i) {
scanf("%d",&fr[i]);
++fr[i];
}
}
Abigail work(){
dijkstra();
}
Abigail outo(){
printf("%lld\n",dis[1]==INF?-1:dis[1]);
}
int main(){
freopen("maze.in","r",stdin);
freopen("maze.out","w",stdout);
into();
work();
outo();
return 0;
}
T3:
题目大意:给定一个序列A以及一个常数k,并定义一个子段的平均值为:
现在要求这个序列的平均值最大的长度在的子段的平均值.
考场得分:50.
考场发现自己只会暴力,然后用线段树优化了一波,时间复杂度为.
正解先提出了一个性质,若没有长度限制的话,那么最大平均值子段的最大值和最小值一定为这个子段的两端.
有了这个性质,我们就可以愉快地将平均值的式子写成:
突然优美了许多,我们只需要再设a数组为A数组的差分数组,就可以将式子写成:
那么考虑二分ans,然后就可以得出,若这个上式大于ans,则ans一定偏小.
那么维护一下这个式子就可以了,时间复杂度.
代码太神了不敢写了.(其实是太懒了)