题目出的挺好的,数学知识较多。虚拟rk:801
A.Creating a Character
题意:给出力量和敏捷两个属性,现在给出技能点数,在必须使用完技能点数的情况下,有多少种情况,力量属性严格大于敏捷。
wa了4次。
细节蛮多的。可以推导出来 (力量-敏捷)+技能点数/2>点在敏捷上的技能点数 就能满足题意。
不过需要特判,敏捷额外的点数不能超过所有技能点数,而且不能为负数。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 int T; ll a, b, c; int main() { T = read(); while (T--) { a = read(); b = read(); c = read(); if (c == 0)printf("%d\n", a>b?1:0); else { ll temp = a - b; if ((temp + c) <= 0)printf("%d\n", 0); else { if (temp > c)printf("%d\n", c+1); else { ll tmepy = (temp + c) / 2; if ((temp + c) % 2)tmepy++; printf("%d\n", tmepy); } } } } return 0; }
B - Zmei Gorynich
题意:龙有n个头,现在有几种攻击可以选择,砍掉di个头,然后龙长出hi个头。
同样是细节数学题目。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 int t; int n, x; struct node { int d, h, dis; }tr[1000]; int main() { t = read(); while (t--) { n = read(); x = read(); int maxn1 = -1; int pos1 = -1; int maxn2 = -1; int pos2 = -1; up(i, 0, n) { tr[i].d = read(); tr[i].h = read(); tr[i].dis = tr[i].d - tr[i].h; if (maxn1 < tr[i].d) { maxn1 = tr[i].d; pos1 = i; } if (maxn2 < tr[i].dis) { maxn2 = tr[i].dis; pos2 = i; } } if (maxn1 >= x) { printf("%d\n", 1); } else { int ans = 0; if (maxn2 <= 0) { printf("%d\n", -1); continue; } if ((x - maxn1) % maxn2 == 0)ans = (x - maxn1) / maxn2; else ans = (x - maxn1) / maxn2 + 1; printf("%d\n",++ans ); } } }
c. 题意:给一个01字符串,求他的字串的二进制等于字串长度的所有情况。
由题意,长度最长为2e5,二进制长度最长20。意思就是说,如果当前为1,那么他往后最长为20。
其次我们需要考虑前导零。加上前导零的影响,我们暴力判断就好了。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 int t; const int N = 2e5 + 10; char s[N]; int main() { t = read(); while (t--) { scanf("%s", s); int n = strlen(s); int num_0 = 0; int ans = 0; up(i, 0, n) { if (s[i] == '0') { num_0++; continue; } int temp = 0; int cnt = 1; up(j, i, n) { temp<<=1; temp |= s[j] == '1' ? 1 : 0; if (temp <= num_0 + j - i + 1)ans++; if(j!=i) cnt <<= 1; if (cnt > (int)2e5 + 1)break; } num_0 = 0; } cout << ans << endl; } }
D:
确实没想到。。推出了只有1,2两种情况,然后想的是交替染色,然而代码写崩了。。
题意:给图染色,唯一的条件就是这个图里面的环不能只有一种颜色。
我们由scc的思想来看,一个环必定由小->大,然后再大->小,所以我们令全部小大染色1,大小染色2。
有向图判环直接拓扑一下就好了。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 int n, m; const int N = 5005; struct { int next, to; }edge[N]; int head[N]; int cnt = 0; int in[N]; int ans[N]; bool flag = 1; void addedge(int u, int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void topo_sort() { queue<int>que; int cnt = 0; upd(i,1, n) { if (!in[i])que.push(i), in[i] = -1; } while (!que.empty()) { cnt++; int s = que.front(); que.pop(); for (int i = head[s]; ~i; i = edge[i].next) { int v = edge[i].to; in[v]--; if (!in[v])que.push(v); } in[s] = -1; } //cout << cnt << endl; if (cnt == n)flag = 0; } int main() { int u, v; n = read(), m = read(); memset(head, -1, sizeof(head)); up(i, 0, m) { u = read(), v = read(); addedge(u, v); in[v]++; ans[i] = (u < v) + 1; } topo_sort(); if (flag) { printf("%d\n", 2); up(i, 0, m)printf("%d ", ans[i]); } else { printf("%d\n", 1); up(i, 0, m)printf("%d ", 1); } }
E:
数论+简单线段树。
题意:给出一堆数字,这堆数字good当且仅当,这堆数字的和的每一位,都出现在了这堆数字的某一个数字的对应位置上。
我们假设某两个数字的同一位置上为a和b(0<=a,b<=9)
我们要使得这个位置的数字不变,那么就有a==0||b == 0,否则,a+b取个位一定是小于a或者b的,那么就需要第三个数字来凑。
因为相加大于十向前进了一位,相当于下一位加1,下一位又是由两个数字相加得到,这个时候无论是下一位是ai+1 ==0||bi+1 ==0,都因为加了1,所以下一位无法想等。而如果下一位是相加大于十,那么当 ai+1 ==9||bi+1 ==9的时候,加一刚好满足,但是又有新的问题,带给了下下位置新的进位,以此类推,一定不满足情况。因为最高位会变成1,这个最高位肯定是当前两个数字都无法拥有的。
故满足的情况只能是,必须一个为零。
那么我们吧1e9拆成10位,个十百千万这样的十颗线段树。
某一段是balance的当且仅当,不为零的数小于等于1。所以我们每一个位置上储存当前最小的值即可。
题目要求求最小的sum,这个时候我们发现,如果一段中,出现某两个数字,同时某一位不为零,那么这段区间一定是unbalanced,所以我们只用贪心,找到两个最小的数字即可。所以我们线段树还需要维护,次小值。
(啊这种多颗线段树并且更新繁琐的拿结构体好方便)
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 int n, m; const int N = 2e5 + 10; struct node { int m1, m2; node operator+(const node &a)const { node now = *this; node res; if (now.m1 < a.m1)res.m1 = now.m1, res.m2 = a.m1; else res.m1 = a.m1, res.m2 = now.m1; res.m2 = min(res.m2, min(now.m2, a.m2)); return res; } }tr[N<<2][10]; int a[N]; void pushup(int root) { upd(i, 0, 9) { tr[root][i] = tr[lrt][i] + tr[rrt][i]; } } void build(int l, int r, int root) { if (l == r) { int temp = a[l]; upd(i, 0, 9) { if(temp%10) tr[root][i] = node{ a[l],inf + 1 }; else tr[root][i] = node{ inf + 1,inf + 1 }; temp /= 10; } return; } int mid = (l + r) >> 1; build(lson); build(rson); pushup(root); } void update(int l, int r, int root, int pos) { if (l == r) { int temp = a[l]; int cnt = 0; upd(i, 0, 9) { if (temp % 10) tr[root][i] = node{ a[l],inf + 1 }; else tr[root][i] = node{ inf + 1,inf + 1 }; temp /= 10; } return; } int mid = (l + r) >> 1; if (pos <= mid)update(lson, pos); else update(rson, pos); pushup(root); } node query(int l, int r, int root, int lf, int rt,int id) { if (lf <= l && r <= rt) { return tr[root][id]; } node ans = { inf+1,inf+1 }; int mid = (l + r) >> 1; if (lf <= mid)ans = ans + query(lson,lf,rt,id); if (rt > mid)ans = ans + query(rson,lf,rt,id); return ans; } int main() { n = read(), m = read(); upd(i, 1, n)a[i] = read(); build(1, n, 1); int op; int l, r; while (m--) { op = read(); l = read(), r = read(); if (op == 1) { a[l] = r; update(1, n, 1, l); } else { int sum = 2*inf+3; upd(i, 0, 9) { node ans = { inf + 1,inf + 1 }; ans = ans + query(1, n, 1, l, r, i); if (ans.m1 != inf + 1 && ans.m2 != inf + 1) sum = min(sum, ans.m1 + ans.m2); } if (sum!=2*inf+3) { printf("%d\n", sum); } else printf("%d\n", -1); } } }
最后一道题。。不会。。等以后更厉害了再说吧。。