题目链接
A. Shuffle Hashing
开场即读加题,全称心态爆炸,上来看了看,签到题,哈希?然后再读了读,尺取吧,过了TEST……然后交,WA2,emmm???然后魔改一下,会不会尺取的时候出了什么问题?魔改,继续……WA2???时间过去了半小时,第一次敲那么久的A…… ,开B,然后回来再写了A(91分钟才读明白题…… )
结果,题目竟然是可以移动位置,但是字母的数目是不会变的,那么根本就不需要尺取,直接暴力找,暴力判断即可……读了假题,就说A为什么那么难……
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e2 + 7;
int N, num[30], cpy[30];
char s[maxN], c[maxN];
inline bool check()
{
for(int i=0; i<26; i++) if(cpy[i]) return false;
return true;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%s", s);
scanf("%s", c);
memset(num, 0, sizeof(num));
int len_1 = (int)strlen(s), len_2 = (int)strlen(c);
for(int i=0; i<len_1; i++)
{
num[s[i] - 'a']++;
}
bool ok = false;
for(int i=0; i<=len_2 - len_1; i++)
{
for(int k=0; k<26; k++) cpy[k] = num[k];
for(int j=i; j<len_2; j++)
{
cpy[c[j] - 'a']--;
if(cpy[c[j] - 'a'] < 0) break;
if(check())
{
ok = true;
break;
}
}
if(ok) break;
}
printf(ok ? "YES\n" : "NO\n");
}
return 0;
}
B. A and B
这题花了五分钟签到。
不过就是补差的过程,我们先假设差值是,然后呢,我们就想办法填上这个差值,使得它们又同时到达一个统一标准,所以列写方程:
也就是说
然后,我们现在就是想知道操作数n的求解。
现在det是已知数,x肯定要找最小,所以把首先满足的所有数打表预处理出来,然后呢,我们找连续的两个数,一定有一个是满足条件的,所以直接找即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int _UP = 1e5 + 7;
ll a, b, det;
int tot;
ll tab[_UP];
int main()
{
int T; scanf("%d", &T);
for(ll i = 1LL; i < _UP; i++)
{
tab[i] = i * (i + 1LL);
}
while(T--)
{
scanf("%lld%lld", &a, &b);
det = abs(a - b);
if(!det) { printf("0\n"); continue; }
det <<= 1;
int id = (int)(lower_bound(tab + 1, tab + 100001, det) - tab);
while((tab[id] - det) % 4)
{
id++;
}
printf("%lld\n", (ll)sqrt(tab[id]));
}
return 0;
}
C. Berry Jam
由于直接开了m2快速链接,我看不到最后一个蓝莓酱的图片,一直懵逼了一会,回去写了A,读了两遍题,最后半小时A,然后呢,找到了些许感觉,在看C,把图片单独提出来看,哦豁!直接枚举两个端点啊!可以知道我们可以固定一个端点,然后在另一个端点去看,同时不要忘记,如果单边端点已经满足条件,需要即时更新答案。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, a[maxN], b[maxN];
unordered_map<int, int> A;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &N);
for(int i=1; i<=N; i++) scanf("%d", &a[i]);
for(int i=N; i>=1; i--) scanf("%d", &b[i]);
A.clear();
int now = 0;
int ans = 0;
for(int i=1; i<=N; i++)
{
if(a[i] == 1) now--;
else now++;
A[now] = i;
if(!now) ans = max(ans, i);
}
now = 0;
for(int i=1; i<=N; i++)
{
if(b[i] == 1) now++;
else now--;
if(A[now]) ans = max(ans, i + A[now]);
if(!now) ans = max(ans, i);
}
printf("%d\n", N * 2 - ans);
}
return 0;
}
D. Segment Tree
比赛的时候没时间了,想到了正解,最后读完题还剩5分钟了呜呜呜……
我们可以按照以往的思路,固定一维,然后去看另一维,同时,题目中似乎隐含的说了,不会有任意端点重合,也就是输入的l、r永远不会有相同的值出现的情况(尝试hack失败)。
然后,首先按照一维排序,我这里按照r端点升序排列。那么,我们现在保证了放进去的点都是按照r端点升序的了,然后我们按照l端点放入,到r端点时候弹出这样的一个差分的思想来解决。
我们按照l端点放入,并且放入的时候,我们找所有的r比l大的,并且他的对应的r还要比目前放入的r要小的,这里就可以维护出来了,因为r是单调的啊。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 5e5 + 7;
int N, root[maxN];
int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
struct node
{
int id, l, r;
node(int a=0, int b=0, int c=0):id(a), l(b), r(c) {}
friend bool operator < (node e1, node e2) { return e1.r < e2.r; }
};
multiset<node> st;
vector<node> add[maxN << 1], del[maxN << 1];
inline void init()
{
for(int i=1; i<=N; i++) root[i] = i;
}
int main()
{
scanf("%d", &N);
init();
int Beg = INF, End = 0;
for(int i=1, l, r; i<=N; i++)
{
scanf("%d%d", &l, &r);
add[l].push_back(node(i, l, r));
del[r].push_back(node(i, l, r));
Beg = min(Beg, l); End = max(End, r);
}
bool flag = true; int line = 0;
for(int i = Beg; i <= End; i++)
{
for(node it : del[i])
{
st.erase(it);
}
for(node it : add[i])
{
multiset<node>::iterator pos = st.lower_bound(node(0, it.l, it.l));
while(pos != st.end() && pos->r < it.r)
{
int u = pos->id, v = it.id;
u = fid(u); v = fid(v);
if(u != v)
{
line++;
root[u] = v;
}
else { flag = false; break; }
pos++;
}
}
for(node it : add[i]) st.insert(it);
}
if(flag && line == N - 1) printf("YES\n");
else printf("NO\n");
return 0;
}
E. Tests for problem D
简单的说一下这道题的题意,就是把D题反过来,现在我们知道这棵树,让我们构造出线段来,满足D题条件,SPJ。
那么,简单构造一下,就是包含的关系了,譬如说样例一:
我们总长是1——12
现在我们给根结点赋值的是9——12,因为10和11分别指代了它的两个直接儿子的开始点位置,然后我们继续这样构造即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 5e5 + 7;
int N, head[maxN], cnt;
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN << 1];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
int siz[maxN], fa[maxN], dir[maxN]; //dir是直接和u相连的点的数量
void pre_dfs(int u, int father)
{
siz[u] = 1; fa[u] = father; dir[u] = 0;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == father) continue;
pre_dfs(v, u);
dir[u] ++;
siz[u] += siz[v];
}
}
struct node
{
int l, r;
node(int a=0, int b=0):l(a), r(b) {}
inline void Out() { printf("%d %d\n", l, r); }
}ans[maxN];
int L;
void dfs(int u, int fail)
{
ans[u] = node(L - dir[u], fail);
L = L - 1 - dir[u];
int Beg = L + 2;
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa[u]) continue;
dfs(v, Beg++);
}
}
inline void init()
{
cnt = 0;
for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
scanf("%d", &N);
init();
for(int i=1, u, v; i<N; i++)
{
scanf("%d%d", &u, &v);
_add(u, v);
}
pre_dfs(1, 0);
L = (N << 1) - 1;
dfs(1, N << 1);
for(int i=1; i<=N; i++) ans[i].Out();
return 0;
}