感觉这一次普及难度很ZZ啊。。。
怎么说呢,考差了(最后一题忘记写朴素DP丢了50分),第三题的BFS也写错了一个if(问题不大),总之,思路上没有问题,主要还是代码能力的问题。。继续加油吧
T1 智障难度。。。只要会编程应该都会做吧。。。我们就跳过此题
又是ZZ难度,嗯,普及T2,一发模拟就可以水过,数据范围 N,Q<=1000, 每一个数的值小于10000000,那么我们就可以模10判相等,复杂度也就 O(N∗Q) ,很容易(我先排了下序,为了保证图书编码最小嘛)
代码:
# include
# include
# include
using namespace std;
const int N = 1e3 + 10;
struct node
{
int val,len;
}a[N];
int n,q,i,pre,len,ans;
bool cmp(node a,node b)
{
return a.val < b.val;
}
int getans(int a,int b,int len)
{
int val = 0,sum = 1;
while (len--)
{
val += (a % 10) * sum;
a /= 10;
sum *= 10;
}
if (val == b) return 1;
else return 0;
}
int main()
{
scanf("%d%d",&n,&q);
for (i = 1;i <= n; i++)
{
scanf("%d",&a[i].val);
int tmp = a[i].val; len = 0;
while (tmp)
{
len++;
tmp /= 10;
}
a[i].len = len;
}
sort(a + 1,a + n + 1,cmp);
for (i = 1;i <= q; i++)
{
scanf("%d%d",&len,&pre);
ans = -1;
for (int j = 1;j <= n; j++)
{
if (a[j].len < len) continue;
if (getans(a[j].val,pre,len)) { ans = a[j].val; break; }
}
printf("%d\n",ans);
}
return 0;
}
难度终于上来了啊,然而这道题呢一眼最短路 or BFS,那么怎么做呢,首先考虑每个格子有颜色,我们可以想到分层图SPFA,对于不同颜色,边长为1,相同颜色边长为0,颜色为白色的,我们可以将它转换成两个点,一个黄点,一个红点,分别转移,但是我们在转移的时候记得if判一下上一次有没有用魔法。BFS同理,BFS我们设一个标记数组,代表走到某个格子是什么颜色的最小花费,然后推队列就行了(打标记的if这里考场ZZ写错了),然后注意一下细节。
代码:
# include
# include
# include
using namespace std;
const int N = 1e2 + 10;
struct node
{
int x,y,cost,col,p;
}q[N * N * 500];
int a[N][N],bz[N][N][4],dir[4][2] = {{0,1},{1,0},{-1,0},{0,-1}};
int n,m,i,ans;
int main()
{
memset(bz,0x3f,sizeof(bz));
scanf("%d%d",&m,&n);
for (i = 1;i <= n; i++)
{
int x,y,tmp;
scanf("%d%d%d",&x,&y,&tmp);
++tmp;
a[x][y] = tmp;
}
int h = 1,t = 1;
bz[1][1][a[1][1]] = 0;
q[h] = (node){1,1,0,a[1][1],0};
while (h <= t)
{
node now = q[h++];
for (i = 0;i < 4; i++)
{
int x1 = now.x + dir[i][0],y1 = now.y + dir[i][1];
if (x1 < 1 || x1 > m || y1 < 1 || y1 > m) continue;
if (!a[x1][y1] && now.p) continue;
if (a[x1][y1] == now.col)
{
int col = now.col;
int cost = now.cost;
if (cost >= bz[x1][y1][col]) continue;
bz[x1][y1][col] = cost;
q[++t] = (node){x1,y1,cost,col,0};
}else
if (a[x1][y1] != now.col && a[x1][y1] != 0)
{
int col = a[x1][y1];
int cost = now.cost + 1;
if (cost >= bz[x1][y1][col]) continue;
bz[x1][y1][col] = cost;
q[++t] = (node){x1,y1,cost,col,0};
}else
if (a[x1][y1] == 0 && now.p == 0)
{
int col = 1;int cost = now.cost + 2;
if (col != now.col) ++cost;
if (cost < bz[x1][y1][col]) //这里注意不要直接continue,不然下个点不能转移,考场这里打错了。。。
{
bz[x1][y1][col] = cost;
q[++t] = (node){x1,y1,cost,col,1};
}
col++; cost = now.cost + 2;
if (col != now.col) ++cost;
if (cost >= bz[x1][y1][col]) continue;
bz[x1][y1][col] = cost;
q[++t] = (node){x1,y1,cost,col,1};
}
}
}
ans = min(bz[m][m][1],bz[m][m][2]);
if (ans > 2 * m * m) puts("-1");
else printf("%d\n",ans);
return 0;
}
此次普及比较厉害的一道题,那么我们题目中直接求有两个最值,一般我们不能直接得到两个最小值,由于题目说我们是能不能到K分,那么很容易想到判定性问题,所以用二分求最小值,DP求最高分然后check。。怎么DP呢,我们可以设f[i]表示跳到i的时候能够得到的最高分,然后两个for循环,找符合范围的可转移的状态,那么这么做的复杂度是 O(N2logMax(Xi)) 的,但是也有60分,满分做法比较好想,由于转移是区间移动且单向( Xi 递增),我们就可以用单调队列来优化,我们多设一个指针,表示即将进入单调队列的数,然后来转移就行了,复杂度就变为 O(NlogMax(Xi)) 。
代码:
# include
# include
# include
using namespace std;
const int N = 5e5 + 10;
struct node
{
int dis,val;
}a[N];
int f[N],q[N];
int n,k,d,maxx;
bool check(int x,int xia)
{
int h = 1,t = 1,ans = 0,i = 0,fir;
f[0] = q[1] = 0;
for (i = 1;a[i].dis < xia && i <= n; i++)
continue; //前面有一些格子的距离小于下界,则是无法跳到,直接去除
fir = i;
for (;i <= n; i++)
{
if (a[i].dis - a[i - 1].dis > (x + d)) break; //如果和前面一个格子距离已经大于上界了,则直接break就好了,后面的肯定都不能转移。
while (a[i].dis - a[fir].dis >= xia && fir < i)
{
while (h <= t && f[q[t]] < f[fir]) t--;
q[++t] = fir++;
}
while (h <= t && a[i].dis - a[q[h]].dis > (x + d)) h++;
if (h > t) f[i] = -0x3f3f3f3f; //当前格子跳不到
else
f[i] = f[q[h]] + a[i].val;
ans = max(ans,f[i]);
}
return ans >= k;
}
int main()
{
scanf("%d%d%d",&n,&d,&k);
for (int i = 1;i <= n; i++)
scanf("%d%d",&a[i].dis,&a[i].val);
int l = 0,r = a[n].dis,ret = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid,max(d - mid,1))) r = mid - 1,ret = mid;
else l = mid + 1;
}
if (check(ret,max(d - ret,1))) printf("%d\n",ret);
else puts("-1");
return 0;
}