选拔可算是结束了,做的不好,是所有人都不好。。。都是比较简单易懂的题。zx大佬因为发烧,带病出征,所以状态比较不好,不然这些题,他肯定是分分钟ak的。。。。最后榜首还是被计科院lb大佬抢去了。。。平凡人第二。。。。不出意外的话,应该可以进了。。。几个ac的题写在这留个纪念吧。。
C题 小Z的集训队考验
拓扑序+dp,可以到达每个点的方案数为其父节点的方案数累加之和。最后扫一边出度为0的点,dp值累加一下就行了。
下面是ac代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <queue>
#include <map>
#include <vector>
#define ll long long
using namespace std;
const int N =3e5+5;
int ver[N<<1], he[N], ne[N<<1];
int tot = 1;
bool vis[N];
int di[N];
int di0[N];
int gg[N];
int ans = 0;
void add(int x, int y)
{
ne[++tot] = he[x];
he[x] = tot;
ver[tot] = y;
}
queue<int> q;
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
di[y]++;
di0[x]++;
}
for (int i = 1; i <= n; i++)
{
if (di[i] == 0 && di0[i]) gg[i] = 1, q.push(i);
}
while(q.size())
{
int te = q.front();
q.pop();
for (int i = he[te]; i; i = ne[i])
{
int y = ver[i];
gg[y] += gg[te];
di[y]--;
if (di[y] == 0)
q.push(y);
}
}
for (int i = 1; i <= n; i++)
if (di0[i] == 0) ans += gg[i];
printf("%d\n", ans);
return 0;
}
E题 小W的字符串游戏
伪装成博弈/线段树的思维题,不难想到,字符串的字典序是越选越小的,这样先手何不直接选一个最小的,往后就没法选了。所以这个题的结论是:如果第i个字母su[i]前面有比它小的字母就输出w,or输出z。
下面是ac代码:
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <queue>
#include <set>
#define ll long long
using namespace std;
typedef unsigned long long ull;
const int N = 1e5+5;
const int inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9+7;
char su[N];
int gg[30];
int ans[N];
int main()
{
int t;
cin >> t;
while(t--)
{
memset(su, 0, sizeof(su));
memset(gg, 0, sizeof(gg));
int n;
scanf("%d", &n);
scanf("%s", su);
for (int i = 0; i < n; i++)
{
if (su[i] == 'a') ans[i] = 1;
else
{
if (gg[su[i]-'a']) ans[i] = 0;
else ans[i] = 1;
}
for (char j = su[i]-'a'+1; j <= 'z'-'a'; j++)
{
gg[j] = 1;
}
}
int q;
scanf("%d", &q);
while(q--)
{
int g;
scanf("%d", &g);
if (ans[g]) printf("z\n");
else printf("w\n");
}
}
return 0;
}
F题 W同学的新画板
裸的线段树区间合并,不多说了。
下面是ac代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <queue>
#include <map>
#include <vector>
#define ll long long
using namespace std;
const int N =5e5+5;
int su[N];
struct Node
{
int l, r;
int sum;
int add;
int ls, rs;
}tr[N<<2];
int mx;
void pushup(int p)
{
tr[p].sum = tr[p<<1].sum + tr[p<<1|1].sum;
tr[p].ls = tr[p<<1].ls;
tr[p].rs = tr[p<<1|1].rs;
if (tr[p<<1].rs == tr[p<<1|1].ls) tr[p].sum--;
}
void build(int p, int l, int r)
{
mx = max(mx, p);
tr[p].l = l; tr[p].r = r;
tr[p].add = -1;
if (l == r)
{
tr[p].ls = tr[p].rs = su[l];
tr[p].sum = 1;
return;
}
int mid = (l + r) >>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
}
void spread(int p)
{
if (tr[p].add == -1) return;
int l = p<<1, r = p<<1|1;
tr[l].sum = 1;tr[l].ls = tr[l].rs = tr[p].add;
tr[r].sum = 1;tr[r].ls = tr[r].rs = tr[p].add;
tr[l].add = tr[r].add = tr[p].add;
tr[p].add = -1;
}
void change(int p, int l, int r, int flag)
{
if (l <= tr[p].l && r >= tr[p].r)
{
tr[p].sum =1;
tr[p].ls = tr[p].rs = flag;
tr[p].add = flag;
return;
}
spread(p);
int mid = (tr[p].r + tr[p].l) >> 1;
if (l <= mid) change(p<<1, l, r, flag);
if (r > mid) change(p<<1|1, l, r, flag);
pushup(p);
}
Node ask(int p, int l, int r)
{
if (l <= tr[p].l && tr[p].r <= r)
{
return tr[p];
}
int mid = (tr[p].l +tr[p].r) >> 1;
spread(p);
if (l > mid)
{
return ask(p<<1|1, l, r);
}
else if (r <= mid)
{
return ask(p<<1, l, r);
}
Node t1 = ask(p<<1, l, r);
Node t2 = ask(p<<1|1, l, r);
Node te;
te.sum = t1.sum + t2.sum;
te.ls = t1.ls;
te.rs = t2.rs;
if (t1.rs == t2.ls) te.sum--;
return te;
}
void print()
{
for (int i = 1; i <= mx; i++)
{
cout << tr[i].l << " " << tr[i].r << " " << tr[i].sum << endl;
cout << tr[i].ls << " " << tr[i].rs << " " << endl;
cout << "--------" << endl;
}
cout << "------------------------" << endl;
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
scanf("%d", &su[i]);
}
build(1, 1, n);
// print();
while(m--)
{
int op, a, b;
scanf("%d%d%d", &op, &a, &b);
if (op == 1)
{
int c;
scanf("%d", &c);
change(1, a, b, c);
// print();
}
else
{
Node te = ask(1, a, b);
printf("%d\n", te.sum);
}
}
return 0;
}
G题 嘉馨学姐又双叒叕来吃包子了
签到尺取,不多说;
下面是ac代码:
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <queue>
#include <set>
#define ll long long
using namespace std;
typedef unsigned long long ull;
const int N = 1e6+5;
const int inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9+7;
int su[N];
map<int, int> mp;
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
int ans = 0;
mp.clear();
for (int i = 1; i <= n; i++)
scanf("%d", &su[i]);
int l = 1;
for (int r = 1; r <= n; r++)
{
mp[su[r]]++;
while(mp[su[r]] > 1)
{
mp[su[l]]--;
l++;
}
ans = max(r - l +1, ans);
}
printf("%d\n", ans);
}
return 0;
}
H题 jzl寻宝记
这 道 题 为 啥 贪 心 可 以 过??本憨批实在不懂啊。是用树形dp过的。如果一个点不取,则左右孩子必取。如果一个点取,左右孩子可取可不取。最后答案是root节点必取的状态。
下面是ac代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <queue>
#include <map>
#include <vector>
#define ll long long
using namespace std;
const int N =128;
const int inf = 200000;
int n;
int su[N];
int dp[N][2];
void dfs(int p)
{
if (p > n) return;
dfs(p*2);
dfs(p*2+1);
if (p*2>n)
{
dp[p][0] = 0;
dp[p][1] = inf;
return;
}
dp[p][0] = (dp[p*2][1] + dp[p*2+1][1]>inf?inf:dp[p*2][1] + dp[p*2+1][1]);
dp[p][1] = min(dp[p*2][0]+dp[p*2+1][0]+max(su[p], max(su[p*2], su[p*2+1])), dp[p*2][1]+dp[p*2+1][1]+su[p]);
dp[p][1] = min(dp[p][1], dp[p*2][0] + dp[p*2+1][1] + max(su[p], su[p*2]));
dp[p][1] = min(dp[p][1], dp[p*2+1][0]+dp[p*2][1] + max(su[p], su[p*2+1]));
}
int main()
{
int k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%d", &su[i]);
if (n&1)
{
dfs(1);
// cout << dp[1][1] << endl;
if (dp[1][1] > k) puts("NO");
else puts("YES");
}
else puts("NO");
return 0;
}
J题 小W的简单游戏
cf原题还是个简化版,签到题,不多数。
下面是ac代码:
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <queue>
#include <set>
#define ll long long
using namespace std;
typedef unsigned long long ull;
const int N = 1e6+5;
const int inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9+7;
int su[10][10];
int id[10];
set <pair<int, int> > ans;
int main()
{
int n;
int m;
int t;
cin >> t;
while(t--)
{
scanf("%d%d", &n, &m);
ans.clear();
for (int i = 1; i <= m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
ans.insert(make_pair(max(x, y), min(x, y)));
}
printf("%d\n", ans.size());
}
return 0;
}
下面是关于网络赛的。。。。这回真的树水到的名额(南京)。。怎么说呢,既然拿到了,那就努力吧。不想多说,现在的水平肯定不行,到哪也是打铁,不过,这一个月还是得努力。不然真的就白费了这个名额了。到时候会更难受,毕竟是弱校。名额异常的宝贵,不能浪费任意一个!加油吧,冲银!!