标签:i+1 cin 定位 name contest 转化 gcd code this
扩展中国剩余定理+斐波那契博弈,没啥好说的,关于斐波那契博弈,详见:传送门
并查集+\(map\)就行,还可以离散化搞一下,把\(i+1\)顺便离散化一下就行。
Code
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e6+5,MAXM = 1e6+5,MOD = 1e9+7,INF = 0x3f3f3f3f,N=100050;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define vii vector<pair<int,int>>
#define vi vector<int>
using namespace std;
int n,q,X[MAXN<<1],len,fa[MAXN<<1],v[MAXN],v2[MAXN],mp[MAXN<<1];
struct Ques{
int z,x;
}Q[MAXM];
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
struct Istream {
template <class T>
Istream &operator >>(T &x) {
static char ch;static bool neg;
for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
x=neg?-x:x;
return *this;
}
}fin;
int main(){
//ios::sync_with_stdio(false);cin.tie(0);
//freopen("../A.in","r",stdin);
//freopen("../A.out","w",stdout);
fin>>n>>q;
for(register int i=1;i<=q;i++){
fin>>Q[i].z>>Q[i].x;
X[++len]=Q[i].x;
X[++len]=Q[i].x+1;
}
sort(X+1,X+1+len);
len=unique(X+1,X+1+len)-X-1;
for(int i=1;i<=len;i++)fa[i]=i;
for(int i=1;i<=q;i++){
v[i] = lower_bound(X+1,X+1+len,Q[i].x)-X;
v2[i] = lower_bound(X+1,X+1+len,Q[i].x+1)-X;
mp[v[i]] = Q[i].x;
mp[v2[i]] = Q[i].x+1;
}
int ans=0;
for(int i=1;i<=q;i++){
if(Q[i].z==1){
if(fa[v[i]]==v[i])fa[v[i]] = find(v2[i]);
}else{
ans=mp[find(v[i])];
if(ans==n+1)printf("-1\n");
else printf("%d\n",ans);
}
}
return 0;
}
不知道啥题,队友说有点坑= =
Code
#include<bits/stdc++.h>
using namespace std;
int main() {
int w; cin>>w;
if(w>=4 && w%2==0) puts("YES");
else puts("NO");
}
KMP模板题。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int q;
int nxtT[N], nxtS[N], nxt[N];
char T[N], S[N];
void Get_next(char *s, int *nxt) {
int j, L = strlen(s + 1);
nxt[1] = j = 0;
for(int i = 2; i <= L; i++) {
while(j && s[i] != s[j + 1]) j = nxt[j];
if(s[i] == s[j + 1]) j++;
nxt[i] = j;
}
}
bool cmp(char *s1, char *s2, int op) {
if(op) memcpy(nxt, nxtS, sizeof(nxtS));
else memcpy(nxt, nxtT, sizeof(nxtT));
int L1 = strlen(s1 + 1), L2 = strlen(s2 + 1);
for(int i = 1, j = 0; i <= L1; i++) {
while(j > 0 && (j == L2 || s1[i] != s2[j + 1])) j = nxt[j];
if(s1[i] == s2[j + 1]) j++;
if(j == L2) return true;
}
return false;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T + 1 >> q;
Get_next(T, nxtT);
int lenT = strlen(T + 1);
while(q--) {
cin >> S + 1;
int lenS = strlen(S + 1);
Get_next(S, nxtS);
if(lenS == lenT) {
if(cmp(S, T, 1)) cout << "jntm!" << '\n';
else cout << "friend!" << '\n';
} else if(lenS < lenT) {
if(cmp(T, S, 1)) cout << "my child!" << '\n';
else cout << "oh, child!" << '\n';
} else {
if(cmp(S, T, 0)) cout << "my teacher!" << '\n';
else cout << "senior!" << '\n';
}
}
return 0;
}
题意:
蔡徐坤的篮球队...
给出\(n\)个数,每个数为\(w_i\),现在对于第\(i\)个位置,找最远的一个\(j\),满足\(w_j\geq w_i+m\)。
思路:
注意到这个\(j\)的选取具有单调性就行了,然后维护后缀最大值二分一下即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 5;
int n, m;
int w[N], mx[N];
bool chk(int x, int i) {
return mx[x] >= w[i] + m;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> w[i];
for(int i = n; i; i--) mx[i] = max(w[i], mx[i + 1]);
for(int i = 1; i <= n; i++) {
int l = i + 1, r = n + 1, mid;
while(l < r) {
mid = (l + r) >> 1;
if(chk(mid, i)) l = mid + 1;
else r = mid;
}
cout << l - 2 - i;
if(i != n) cout << ' ';
}
return 0;
}
题意:
给出一颗\(n\)个结点的树,每个结点有权值\(p_i\)。
之后回答\(q\)个询问,每个询问给出\(v_i,k_i\),回答距离点\(v_i\)距离不大于\(k_i\)的所有点的权值和。
其中\(q\leq 5000,0\leq k_i\leq 100\)。
思路:
总的来说,就是利用容斥+拆分询问的思想,有时候一个询问比较复杂,可以考虑将询问拆分成多个,每次只回答一些子问题就行了。这跟多维偏序有点像。。
注意一下细节,比如\(k=0\)的情况什么的,以及跳到根就没必要再跳了。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000005;
template <class T>
inline void read(T& x) {
static char c;
x = 0;
bool sign = 0;
while (!isdigit(c = getchar()))
if (c == '-')
sign = 1;
for (; isdigit(c); x = x * 10 + c - '0', c = getchar())
;
if (sign)
x = -x;
}
int n;
ll a[N];
struct Edge{
int v, next;
}e[N << 1];
int head[N], tot;
void adde(int u, int v) {
e[tot].v = v; e[tot].next = head[u]; head[u] = tot++;
}
int fa[N], d[N];
void getfa(int u, int Fa) {
fa[u] = Fa; d[u] = d[Fa] + 1;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v != Fa) getfa(v, u);
}
}
struct Query{
int k, op, id;
};
vector <Query> q[N];
ll c[N];
int lowbit(int x) {return x & (-x);}
void add(int x, ll v) {
for(; x < N; x += lowbit(x)) c[x] += v;
}
ll sum(int x) {
ll ans = 0;
for(; x; x -= lowbit(x)) ans += c[x];
return ans;
}
ll sum(int l, int r) {
return sum(r) - sum(l - 1);
}
ll res[N];
void dfs(int u, int fa) {
for(auto it : q[u]) {
int k = it.k, id = it.id, op = it.op;
res[id] -= op * sum(d[u], d[u] + k);
}
add(d[u], a[u]);
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v != fa) dfs(v, u);
}
for(auto it : q[u]) {
int k = it.k, id = it.id, op = it.op;
res[id] += op * sum(d[u], d[u] + k);
}
}
int main() {
// freopen("input.in", "r", stdin);
read(n);
for(int i = 1; i <= n; i++) read(a[i]);
memset(head, -1, sizeof(head));
for(int i = 1; i < n; i++) {
int u, v; read(u), read(v);
adde(u, v); adde(v, u);
}
getfa(1, 0);
int t; read(t);
for(int i = 1; i <= t; i++) {
int v, k; read(v), read(k);
q[v].push_back({k, 1, i});
while(fa[v] && (--k) >= 0) {
q[fa[v]].push_back({k, 1, i});
if(k - 1 >= 0) q[v].push_back({k - 1, -1, i});
v = fa[v];
}
}
// for(int i = 1; i <= tot; i++) {
// cout << q[i].v << ' ' << q[i].k << ' ' << q[i].op << '\n';
// }
dfs(1, 0);
for(int i = 1; i <= t; i++) {
printf("%lld\n", res[i]);
}
return 0;
}
在回文自动机上面\(dfs\)一下,统计一下即可。利用一个桶来维护一下当前出现的次数,注意还要乘上回文串出现的次数。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
int n;
char s[N];
namespace PAM{
int ch[N][26], fail[N], len[N], st[N], cnt[26], num[N];
int sz, n, last;
ll ans, cur;
int New(int l, int f) {
memset(ch[++sz], 0, sizeof(ch[sz]));
len[sz] = l, fail[sz] = f;
return sz;
}
void init() {
sz = -1; ans = cur = 0;
New(0, 1); last = New(-1, 0);
st[n = 0] = -1;
memset(cnt, 0, sizeof(cnt));
memset(num, 0, sizeof(num));
}
int getf(int x) {
while(st[n - len[x] - 1] != st[n]) x = fail[x];
return x;
}
bool Insert(int c) { //int
st[++n] = c;
int x = getf(last);
bool F = 0;
if(!ch[x][c]) {
F = 1;
int f = getf(fail[x]);
ch[x][c] = New(len[x] + 2, ch[f][c]);
}
last = ch[x][c];
++num[last];
return F;
}
void count() {
for(int i = sz; i >= 2; i--) num[fail[i]] += num[i];
}
void debug() {
cout << sz << '\n';
for(int i = 1; i <= sz; i++) cout << num[i] << ' ';
cout << '\n';
}
void dfs(int u) {
for(int i = 0; i < 26; i++) {
int v = ch[u][i];
if(v) {
if(++cnt[i] == 1) ++cur;
ans += cur * num[v];
dfs(v);
if(--cnt[i] == 0) --cur;
}
}
}
};
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> s + 1;
n = strlen(s + 1);
PAM::init();
for(int i = 1; i <= n; i++) {
PAM::Insert(s[i] - 'a');
}
PAM::count();
PAM::dfs(0);
PAM::dfs(1);
cout << PAM::ans;
return 0;
}
参见:传送门
题意:
给出一个\(n\)的排列,现在回答多个询问,对于每个询问\([l,r]\),回答有多少对\((i,j)\),满足\(l\leq i < j\leq r\)且\(min(p_i, p_j)=gcd(p_i,p_j)\)。
思路:
注意到\(min(p_i, p_j)=gcd(p_i,p_j)\)其实就是\(a_i,a_j\)为倍数关系,因为\(1\)到\(n\)的排列中这样的倍数对数量级为\(O(nlogn)\)的,所以我们可以提前找出来所有的对数。
然后将询问离线,就相当于处理一个简单的二位偏序问题了。
有很多种做法,余独爱树状数组。
Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
int n, m;
int a[N], p[N];
vector <int> v[N];
vector <pii> Q[N];
int ans[N];
int c[N];
int lowbit(int x) {return x & (-x);}
void add(int x, int v) {
for(; x < N; x += lowbit(x)) c[x] += v;
}
int query(int x) {
int ans = 0;
for(; x; x -= lowbit(x)) ans += c[x];
return ans;
}
int query(int l, int r) {
return query(r) - query(l - 1);
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> a[i]; p[a[i]] = i;
}
for(int i = 1; i <= n; i++) {
for(int j = 2 * i; j <= n; j += i) {
int x = p[i], y = p[j];
if(x > y) swap(x, y);
v[y].push_back(x);
}
}
for(int i = 1; i <= m; i++) {
int l, r; cin >> l >> r;
Q[r].push_back(MP(l, i));
}
for(int i = 1; i <= n; i++) {
for(auto it : v[i]) add(it, 1);
for(auto it : Q[i]) {
int L = it.fi, id = it.se, R = i;
ans[id] = query(L, R);
}
}
for(int i = 1; i <= m; i++) cout << ans[i] << '\n';
return 0;
}
题意:
现在有一个\(vector\),现在每次访问的时候会随机访问一个元素。
然后现在用这个\(vector\)去找子树最大深度,每到一个结点时,先找出\(size\),然后循环\(size\)次去找儿子\(dfs\)下去。
最后问得到的最大深度与实际真正的最大深度相等的概率为多少。
思路:
这个题我没想出来,dp这方面太弱了QAQ。
首先注意这一点:
这不是什么励志鸡汤,这一点可以告诉我们将问题转化一下,求出失败的概率,那么减一下就有成功的概率了。
考虑树形dp,设\(dp[u]\)表示从\(u\)出发,能成功到达最大深度的概率。初始化,对于一些深度为最大深度的叶子结点,它们的值为\(1\),其余全是\(0\)。
我们考虑对于每个结点,我们算它们失败一次的概率。那么就有:\(p=1-\frac{1}{size}\sum_{v\in son}dp[v]\)。这个还是比较好算的。
那么既然不能成功,就说明每次失败,那么全部失败的概率就为\(p^{size}\)。所以\(dp[u]=1-p^{size}\)。
转化一下问题过后,就变得很简单了,如果硬要死磕成功,那么就还有第几次成功的问题,或者成功过后再成功什么乱七八糟的,就很难搞了。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5, MOD = 1e9 + 7;
ll qp(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
int n;
vector <int> g[N];
int sz[N], dep[N];
int Max;
void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
for(auto v : g[u]) {
if(v == fa) continue;
dfs(v, u);
++sz[u];
}
}
int dp[N];
int add(int x, int y) {
x += y;
if(x >= MOD) x -= MOD;
return x;
}
int mul(ll a, ll b) {
a *= b;
return a % MOD;
}
void dfs2(int u, int fa) {
if(dep[u] == Max) {
dp[u] = 1; return ;
}
int p = 0;
for(auto v : g[u]) {
if(v == fa) continue;
dfs2(v, u);
p = add(p, dp[v]);
}
p = mul(p, qp(sz[u], MOD - 2));
p = 1 - p + MOD;
int k = qp(p, sz[u]);
dp[u] = (1 - k + MOD) % MOD;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for(int i = 1; i < n; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
Max = *max_element(dep + 1, dep + n + 1);
dfs2(1, 0);
cout << dp[1];
return 0;
}
题意:
给出\(n\)个点,\(n\leq 1000\),现在要在二维平面上找一个点\((x_0,y_0)\),使得对于每个点\((x_i,y_i)\),都存在一个点\((x_j,y_j)\)关于\((x_0,y_0)\)中心对称。
如果不存在一个点\((x_j,y_j)\),那么就称\((x_i,y_i)\)为孤儿点。
现在问怎么选择\((x_0,y_0)\),使得孤儿点最少。
思路:
注意到如果这个点为某个\((x_i,y_i)\),那么还需要特判一下再更新答案。
详见代码:
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1005;
map <int, map<int, int>> mp, cnt;
struct node{
int x, y;
}a[N];
int n;
bool chk(int x, int y) {
return x % 2 == 0 && y % 2 == 0 && mp[x / 2][y / 2] == 1;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y;
mp[a[i].x][a[i].y] = 1;
}
int ansx, ansy;
int ans = 0;
for(int i = 1; i <= n; i++) {
for(int j = i; j <= n; j++) {
int x = a[i].x + a[j].x, y = a[i].y + a[j].y;
cnt[x][y]++;
if(cnt[x][y] > ans) {
ans = cnt[x][y];
ansx = x, ansy = y;
} else if(cnt[x][y] == ans && !chk(x, y)) {
ans = cnt[x][y];
ansx = x, ansy = y;
}
}
}
ans = n - 2 * cnt[ansx][ansy];
if(chk(ansx, ansy)) ++ans;
cout << ans;
return 0;
}
序列自动机预处理下一位,然后在每一位都有两种选择,等于或大于,跟着\(t\)串跑一遍就行了。
注意一下细节,注意字典序不能相等,只有严格大于。
详见代码吧:
Code
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int nxt[N][26], last[26];
char s[N], t[N];
int n, m;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
cin >> s + 1 >> t + 1;
for(int i = n; i >= 0; i--) {
int p = s[i] - 'a';
for(int j = 0; j < 26; j++) nxt[i][j] = last[j];
last[p] = i;
}
int i = 0;
int ans = -1;
for(int j = 1; j <= m; j++) {
int tmp = N, p = t[j] - 'a';
for(int k = p + 1; k < 26; k++) if(nxt[i][k]) tmp = min(tmp, nxt[i][k]);
if(tmp < N) ans = max(ans, n - tmp + j);
i = nxt[i][p];
if(!i) break;
if(j == m && i < n) {
ans = max(ans, m + n - i);
}
}
cout << ans;
return 0;
}
The Preliminary Contest for ICPC Asia Xuzhou 2019
标签:i+1 cin 定位 name contest 转化 gcd code this
原文地址:https://www.cnblogs.com/heyuhhh/p/11517259.html