题目链接
A Sagheer and Crossroads
每一个路口有交通灯,以及人行道,问给出的情况下会不会出现交通事故。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 int val[50 ][50 ];void solve () { sa (val[1 ][4 ]); sa (val[1 ][3 ]); sa (val[1 ][2 ]); sa (val[1 ][1 ]); sa (val[2 ][1 ]); sa (val[2 ][4 ]); sa (val[2 ][3 ]); sa (val[2 ][2 ]); sa (val[3 ][2 ]); sa (val[3 ][1 ]); sa (val[3 ][4 ]); sa (val[3 ][3 ]); sa (val[4 ][3 ]); sa (val[4 ][2 ]); sa (val[4 ][1 ]); sa (val[4 ][4 ]); repp (i,1 ,4 ) { if (val[i][i]) { repp (k,1 ,4 ) { if (i==k)continue ; if (val[i][k]) { puts ("YES" ); return ; } } repp (j,1 ,4 ) { if (i==j)continue ; if (val[j][i]) { puts ("YES" ); return ; } } } } puts ("NO" ); }
B Sagheer, the Hausmeister
一幢楼有左右两个楼梯,中间是房间。一个人站在一层的左楼梯上,现在要把这幢楼的所有房间的灯都关掉,问最少走多少距离。楼的层数$N<15$,每层楼的房间数$M<100$。
DP,做的时候有些麻烦,因为最终的位置不一定是最高层。题解直接是暴力选择$O(2^n*n)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 int n, m;char val[150 ][150 ];int dp[150 ][2 ];void solve () { sa (n), sa (m); repp (i, 1 , n) { scanf ("%s" , val[i] + 1 ); } int up = 0 ; repp (i, 1 , n) { int flag = 0 ; for (int k = 1 ; k <= m + 2 ; k++) { if (val[i][k] == '1' ) { flag = 1 ; } } if (flag) { up = i; break ; } } if (up == 0 ) { puts ("0" ); return ; } for (int i = n; i >= up; i--) { if (i == up) { int left = -1 , right = -1 ; int cnt = 0 ; for (int k = 1 ; k <= m + 2 ; k++) { if (val[i][k] == '1' ) { right = k; } } for (int k = m + 2 ; k >= 1 ; k--) { if (val[i][k] == '1' ) { left = k; } } left = m + 2 - left; int res = dp[i + 1 ][0 ] + (right-1 ) + (up!=n); if (up!=n)res = min (res, dp[i + 1 ][1 ] + (left) + 1 ); printf ("%d\n" , res); return ; } else if (i == n) { int p = 0 ; for (int k = 1 ; k <= m + 2 ; k++) { if (val[i][k] == '1' ) { p = k; } } if (p != 0 ) { dp[i][0 ] = (p - 1 ) * 2 ; } dp[i][1 ] = m + 1 ; } else { int left = -1 , right = -1 ; int cnt = 0 ; for (int k = 1 ; k <= m + 2 ; k++) { if (val[i][k] == '1' ) { right = k; } } if (right == -1 ) { dp[i][0 ] = dp[i + 1 ][0 ] + 1 ; dp[i][0 ] = min (dp[i][0 ], dp[i + 1 ][1 ] + m + 2 ); dp[i][1 ] = dp[i + 1 ][1 ] + 1 ; dp[i][1 ] = min (dp[i][1 ], dp[i + 1 ][0 ] + m + 2 ); continue ; } for (int k = m + 2 ; k >= 1 ; k--) { if (val[i][k] == '1' ) { left = k; } } left = m + 2 - left; dp[i][0 ] = dp[i + 1 ][0 ] + (right-1 ) * 2 + 1 ; dp[i][0 ] = min (dp[i][0 ], dp[i + 1 ][1 ] + m + 1 + 1 ); dp[i][1 ] = dp[i + 1 ][1 ] + (left) * 2 + 1 ; dp[i][1 ] = min (dp[i][1 ], dp[i + 1 ][0 ] + m + 1 + 1 ); } } puts ("0" ); }
C Sagheer and Nubian Market
有$n$个物品以及你拥有的总钱数$S$,现在每个物品的价钱是根据你最终购买物品的数量决定的,问最多你可以购买多少个。
二分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 ll n, S; ll val[maxn]; ll v[maxn]; bool check (ll num) { repp (i, 1 , n) { v[i] = 1LL * val[i] + 1LL * i*num; } sort (v + 1 , v + n + 1 ); int cnt = 0 ; ll sum = S; repp (i, 1 , n) { if (sum >= v[i]) { sum -= v[i]; cnt++; } else { break ; } } return cnt >= num; } void solve () { scanf ("%lld%lld" , &n, &S); repp (i, 1 , n) { scanf ("%lld" , &val[i]); } ll le = 0 , ri = n; while (le<ri) { ll mid = (le + ri + 1 ) / 2 ; if (check (mid)) { le = mid; } else { ri = mid - 1 ; } } printf ("%lld " , le); if (le == 0 ) { printf ("0" ); return ; } repp (i, 1 , n) { v[i] = 1LL * val[i] + 1LL * i*le; } sort (v + 1 , v + n + 1 ); int cnt = 0 ; ll sum = S; repp (i, 1 , le) { sum -= v[i]; } printf ("%lld" , S - sum); }
D Sagheer and Kindergarten
题意是幼儿园有$n$个小朋友和$m$个玩具,小朋友会按照时间顺序提出请求玩哪一个玩具的请求,如果一个孩子得到了他所请求的所有玩具,那么他玩完会归还。否则他就继续等,也不会提出玩其他玩具的请求。如果有一些孩子永远无法得到他们请求的玩具,那么他们会哭。
现在给出前面的$k$个请求,保证不会有哭的情况。有$q$个询问,每个询问代表添加了最后的请求之后,计算有多少哭的孩子。
把每一个孩子当作点,当孩子等待另一个孩子的玩具的时候,连一条边。出现哭的情况即是出现了环。
每一个询问,就是看这两个点是否在一棵树中。用dfs序来判断是否是根节点与子节点的关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 int n,m,k,q;int fa[maxn],who[maxn];int in[maxn],out[maxn];vector<int >edge[maxn]; int idx;void dfs (int x,int fa) { idx++; in[x]=idx; for (int i=0 ;i<edge[x].size ();i++) { int nxt=edge[x][i]; if (nxt==fa)continue ; dfs (nxt,x); } out[x]=idx; } void solve () { sa (n),sa (m),sa (k),sa (q); repp (i,1 ,k) { int x,y; sa (x),sa (y); if (who[y]) { fa[x]=who[y]; } who[y]=x; } repp (i,1 ,n) { edge[fa[i]].push_back (i); } idx=0 ; repp (i,1 ,n) { if (in[i]==0 ) { dfs (i,-1 ); } } repp (i,1 ,q) { int x,y; sa (x),sa (y); y=who[y]; if (in[x]<=in[y]&&out[x]>=out[y]) { printf ("%d\n" , out[x]-in[x]+1 ); } else { puts ("0" ); } } }
E Sagheer and Apple Tree
一颗树,每个节点上有$p_i$数量的苹果,每个玩家有两种操作,1.吃掉叶子节点上任意数量的苹果。2.从父节点移到任意数量的苹果到其中一个子节点上。现在后手有一个机会去交换两个节点的数量,问后手有多少个交换节点的方案可以赢。
每个叶子节点的深度的奇偶性是一致的,阶梯博弈,只不过拿到了树上面。(如果不一致不知道怎么做了)。
然后就看最终和叶子节点深度的奇偶性一致的节点异或起来,为$0$后手胜。算方案数的话,枚举,加上另一个集合的对应数字的数量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 int ans,res;int n;int maxx;int val[maxn];int dep[maxn];vector<int >edge[maxn]; map<int ,int >cnt[2 ]; int c0,c1;void dfs (int x) { for (int i=0 ;i<edge[x].size ();i++) { int nxt=edge[x][i]; dfs (nxt); dep[x]=max (dep[x],dep[nxt]+1 ); } maxx=max (maxx,dep[x]); cnt[dep[x]&1 ][val[x]]++; if (dep[x]&1 )c1++; else c0++; } void solve () { sa (n); repp (i,1 ,n) { sa (val[i]); } repp (i,2 ,n) { int x; sa (x); edge[x].push_back (i); } maxx=0 ; dfs (1 ); for (int i=1 ;i<=n;i++) { if (dep[i]%2 ==0 ) { ans^=val[i]; } } ll res=0 ; if (ans==0 ) { res+=1LL *c0*(c0-1 )/2 ; res+=1LL *c1*(c1-1 )/2 ; } for (int i=1 ;i<=n;i++) { if (dep[i]%2 ==0 ) { int tmp=ans^val[i]; res+=cnt[1 ][tmp]; } } printf ("%lld\n" , res); }