A
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define pb push_back #define inf 0x3f3f3f3f //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; get min const double eps = 1.0e-10; const double EPS = 1.0e-4; typedef pair<int, int> pairint; typedef long long ll; typedef unsigned long long ull; //const int maxn = 3e5 + 10; const int turn[4][2] = {{0, 1}, { 1, 0}, { 0, -1}, { -1, 0}}; //priority_queue<int, vector<int>, less<int>> que; //next_permutation int main() { string f; cin >> f; int len = f.size(); int flag = 1; int numa = 0; int numb = 0; int numc = 0; int now = 0; for (int i = 0; i < len; i++) { if (f[i] - 'a' < now) { flag = 0; break; } else { now = max(now, f[i] - 'a'); } } if (!flag) { cout << "NO" << endl; return 0; } for (int i = 0; i < len; i++) { if (f[i] == 'a') { numa++; } else if (f[i] == 'b') { numb++; } else { numc++; } } if (numa < 1 || numb < 1) { cout << "NO" << endl; return 0; } if (numc == numa || numc == numb) { cout << "YES" << endl; } else { cout << "NO" << endl; } }
B
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define pb push_back #define inf 0x3f3f3f3f //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; get min const double eps = 1.0e-10; const double EPS = 1.0e-4; typedef pair<int, int> pairint; typedef long long ll; typedef unsigned long long ull; //const int maxn = 3e5 + 10; const int turn[4][2] = {{0, 1}, { 1, 0}, { 0, -1}, { -1, 0}}; //priority_queue<int, vector<int>, less<int>> que; //next_permutation priority_queue<ll, vector<ll>, less<ll>> que; ll a[1005]; ll b[1005]; int main() { ll anser = 0; ll n, k1, k2; cin >> n >> k1 >> k2; for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } for (int i = 1; i <= n; i++) { scanf("%lld", &b[i]); que.push(abs(a[i] - b[i])); anser += abs(a[i] - b[i]) * abs(a[i] - b[i]); } int cur = k1 + k2; while (cur) { ll now = que.top(); que.pop(); if (now == 0) { cur--; que.push(1); anser += 1; } else { cur--; que.push(now - 1); anser -= 1LL * now * now; anser += 1LL * (now - 1) * (now - 1); } } cout << anser << endl; }
C
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define pb push_back #define inf 0x3f3f3f3f //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; get min const double eps = 1.0e-10; const double EPS = 1.0e-4; typedef pair<int, int> pairint; typedef long long ll; typedef unsigned long long ull; //const int maxn = 3e5 + 10; const int turn[4][2] = {{0, 1}, { 1, 0}, { 0, -1}, { -1, 0}}; //priority_queue<int, vector<int>, less<int>> que; //next_permutation priority_queue<ll, vector<ll>, less<ll>> que; vector<ll> ans; int main() { //freopen("out.txt","w",stdout); ll x, d; cin >> x >> d; // if(x<=10000) // { // for(ll i=1;x;i+=d+1) // { // cout<<i<<" "; // x--; // } // return 0; // } ll cur = 1; if (x == 1) { cout << 1 << endl; cout << 1 << endl; return 0; } if (x & 1) { ans.push_back(1e17 - 1); x -= 1; } for (ll i = 0; i <= 32; i++) { if ((1LL << i)&x) { que.push(i); } } while (!que.empty()) { ll number = que.top(); que.pop(); for (ll i = 1; i <= number; i++) { ans.push_back(cur); } cur += d; ans.push_back(cur); cur += d; } cout << ans.size() << endl; for (ll ch : ans) { cout << ch << " "; } }
D
给你一个完全二叉树有三种操作
1.把值为X的节点所在当前层 移动K次
2.把值为X的节点所在当前层 移动K次 子树也跟着移动
3.询问你值为X所在结点到根节点路径上节点的值
shift[i]表示第i层移动的次数
第二个操作很好处理 第三个操作就是在第二个操作上pushdown 下一层移动的次数是上一层的两倍
(记得取模操作)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define pb push_back #define inf 0x3f3f3f3f //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; get min const double eps = 1.0e-10; const double EPS = 1.0e-4; typedef pair<int, int> pairint; typedef long long ll; typedef unsigned long long ull; //const int maxn = 3e5 + 10; const int turn[4][2] = {{0, 1}, { 1, 0}, { 0, -1}, { -1, 0}}; //priority_queue<int, vector<int>, less<int>> que; //next_permutation int Q; int T; ll level; ll X, K; ll lenth, position; ll shift[70]; void update(ll x, ll K) { shift[x] += K; shift[x] %= (1LL << (x - 1)); } void pushdown(ll x, ll K) { shift[x] += K; shift[x] %= (1LL << (x - 1)); if (x + 1 < 61) { K = (K << 1); pushdown(x + 1, K); } } ll getpos(ll level, ll x) { ll l = 1LL << (level - 1); ll r = (1LL << level) - 1; ll now = x + shift[level]; if (l <= now && now <= r) { return now; } if (now < l) { ll cha = l - now - 1; return r - cha; } else { ll cha = now - r - 1; return l + cha; } } void print(ll level, ll pos) { if (level == 1) { cout << 1; return ; } ll now = pos - shift[level]; ll l = 1LL << (level - 1); ll r = (1LL << level) - 1; if (l <= now && now <= r) { cout << now << " "; print(level - 1, pos / 2); return; } if (now < l) { ll cha = l - now - 1; cout << r - cha << " "; } else { ll cha = now - r - 1; cout << l + cha << " "; } print(level - 1, pos / 2); return ; } int main() { //freopen("out.txt","w",stdout); cin >> Q; while (Q--) { int T; scanf("%d %lld", &T, &X); for (ll i = 61; i >= 1; i--) { if ((1LL << (i - 1))&X) { if (((1LL << i)&X) == 0) { level = i; break; } } } //cout<<level<<" "; if (T == 1) { scanf("%lld", &K); if (X == 1) { continue; } K %= 1LL << (level - 1); update(level, K); } else if (T == 2) { scanf("%lld", &K); if (X == 1) { continue; } K %= 1LL << (level - 1); pushdown(level, K); } else { if (X == 1) { cout << 1 << endl; continue; } cout << X << " "; position = getpos(level, X); //cout << position; print(level - 1, position / 2); cout << endl; } } }
E
F
先来做F的简化版
http://codeforces.com/contest/459/problem/E
求有向图的最长严格递增路径
dp[i]表示以第i条边为结尾的最长路径 g[i]表示以i结点为结尾的最长路径
所以dp[i]=dp[edge[i].from]+1即以第i条边结尾的答案是以该边from结尾的最长路径长度+其本身
首先排序 相同大小的边之间是不会相连的
而如果每遍历一条边就g[edge[i].to]=max(g[edge[i].to],dp[i])的话 如果edge[i+1].from=edge[i].to 就变成这两条边相连了所以相同值的边要分处理
复杂度NLOGN
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define MAX 300007 using namespace std; int n, m; int dp[MAX], g[MAX]; struct Edge { int u, v, w; bool operator < ( const Edge& a ) const { return w < a.w; } } e[MAX]; int main ( ) { while ( ~scanf ( "%d%d" , &n , &m ) ) { for ( int i = 0 ; i < m ; i++ ) { scanf ( "%d%d%d" , &e[i].u , &e[i].v , &e[i].w ); } sort ( e , e + m );// 排序 int t = 0; e[m].w = -1;//使得最后一组边也能更新 int ans = 0; //答案 for ( int i = 0 ; i < m ; i++ ) //从小到大枚举 { int v = e[i].v; int u = e[i].u; int w = e[i].w; dp[i] = g[e[i].u] + 1; //以第i条边结尾的答案是以e[i].from节点为结尾的最长路径+它本身 if ( e[i].w != e[i + 1].w ) { for ( int j = t ; j <= i ; j++ ) //处理相同边 { g[e[j].v] = max ( g[e[j].v] , dp[j] );//更新e[i].to的答案 以便处理下一组边 } t = i + 1;//重置相同边的起点 } ans = max ( ans , dp[i] ); } printf ( "%d\n" , ans ); } }
现在来做F
如果用上面的方法来做 不能保证下标不能有逆序对这个条件
如果去掉edge[i].from=edge[j].to这个条件的话 这道题就变成一道裸的LIS
如果用来DP的话 普通的dp[i][j]数组表示以i为结尾的权重最大为j的最长递增路径长度 因为i和j都是1e5的会炸
但是用MAP来存的话 因为每个dp[i]表示的都是一个树状数组 每次插入和询问都是LOGN的 所以最多只会涉及到NLOGN个节点 可以接受
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define pb push_back #define inf 0x3f3f3f3f //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; get min const double eps = 1.0e-10; const double EPS = 1.0e-4; typedef pair<int, int> pairint; typedef long long ll; typedef unsigned long long ull; //const int maxn = 3e5 + 10; const int turn[4][2] = {{0, 1}, { 1, 0}, { 0, -1}, { -1, 0}}; //priority_queue<int, vector<int>, less<int>> que; //next_permutation const int N = 1e5 + 5; map<int, int> bits[N]; int query(int u, int x) { int ans = 0; while (x) { ans = max(ans, bits[u][x]); x -= x & -x; } return ans; } void update(int u, int x, int v) { while (x < N) { bits[u][x] = max(bits[u][x], v); x += x & -x; } } int main() { int n, m, u, v, w; int anser = 0; int cur; scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { scanf("%d%d%d", &u, &v, &w); w++; cur = query(u, w - 1) + 1; update(v, w, cur); anser = max(anser, cur); } printf("%d\n", anser); return 0; }
用主席树来做的话 其实和MAP DP递推是同理的 只建立需要的节点 其他节点忽略
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<cstdio> #include<algorithm> #define lowbit(x) (x&-x) using namespace std; const int maxn=100010; int n,m,f[maxn],rt[maxn],sz; struct tree{int l,r,mx;}t[maxn*20]; void insert(int& k,int l,int r,int x,int y){ if(!k)k=++sz;t[k].mx=max(t[k].mx,y); if(l==r)return; int mid=(l+r)>>1; if(x<=mid)insert(t[k].l,l,mid,x,y); else insert(t[k].r,mid+1,r,x,y); } int query(int k,int l,int r,int x){ if(l==r)return t[k].mx; int mid=(l+r)>>1; if(x<=mid)return query(t[k].l,l,mid,x); else return max(t[t[k].l].mx,query(t[k].r,mid+1,r,x)); } int main(){ scanf("%d%d",&n,&m); int ans=0; for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); f[i]=query(rt[u],1,100000,w-1)+1; insert(rt[v],1,100000,w,f[i]); ans=max(ans,f[i]); } printf("%d",ans); return 0; }