A
#include <cstdio>
#include <cmath>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x) memset(Arr, x, sizeof(Arr))
#define REP(i, x, n) for(int i = x; i < n; ++i)
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
int n, m;
int main(){
int t; scanf("%d", &t);
while(t--){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
int num = c / 4;
int x = num - b;
int y = num - a / 2;
printf("%d\n", num - x - y);
}
return 0;
}
/**************************************************************
Problem: 1224
User: Yokile
Language: C++
Result: Accepted
Time:0 ms
Memory:1696 kb
****************************************************************/
B
参考官方题解:
令 d = abs(x1-x2)+abs(y1-y2)首先判断(n+1)/2 >= d,先手可不可以从一个点走到另一个点 :
如果不可以,则先手可以多得 n&1 分(因为劣势者可以选择逃离)
如果可以,考虑 d 的奇偶性:如果 d 为奇数(先手可以先踩到后手覆盖过的点):
如果 n 为奇数,先手可以多得 2 分,否则平。否则(d 为偶数)
:如果 n 为奇数,先手可以多得 1 分,否则后手可以多得 1 分。
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define LL long long
int main(){
int t; scanf("%d", &t);
while(t--){
LL n, x1, x2, y1, y2;
scanf("%lld%lld%lld%lld%lld", &n, &x1, &y1, &x2, &y2);
LL d = abs(x1 - x2) + abs(y1 - y2);
LL ans = -1;
if((n + 1) / 2 >= d){
if(d % 2 == 0){
ans = 1;
}else{
if(n & 1) ans = 2;
}
}else if(n & 1){
ans = 1;
}
printf("%lld\n", ans);
}
return 0;
}
这题还是不难的,- - 、果然还是萌新阿
C
这题也就是简单地递推, 然后乘法原理即可
#include <cstdio>
#include <cmath>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x) memset(Arr, x, sizeof(Arr))
#define REP(i, x, n) for(int i = x; i < n; ++i)
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
const int MOD = 10007;
int n;
LL dp[30];
int main(){
dp[0] = 0, dp[1] = 1, dp[2] = 2, dp[3] = 4;
for(int i = 4; i <= 20; ++i)
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
int t; scanf("%d", &t);
while(t--){
scanf("%d", &n);
LL tot = 1;
REP(i, 1, n){
int x; scanf("%d", &x);
tot = (tot * dp[x]) % MOD;
}
printf("%lld\n", tot);
}
return 0;
}
/**************************************************************
Problem: 1226
User: Yokile
Language: C++
Result: Accepted
Time:0 ms
Memory:1696 kb
****************************************************************/
D
#include <cstdio>
#include <cmath>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x) memset(Arr, x, sizeof(Arr))
#define REP(i, x, n) for(int i = x; i < n; ++i)
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
int n, m;
int main(){
int t; scanf("%d", &t);
while(t--){
LL a, b, c; scanf("%lld%lld%lld", &a, &b, &c);
LL sum = a * b;
sum = sum + (a / 10 / 3) * c;
printf("%lld\n", sum);
}
return 0;
}
/**************************************************************
Problem: 1227
User: Yokile
Language: C++
Result: Accepted
Time:0 ms
Memory:0 kb
****************************************************************/
E
这题貌似标程除了问题 题目还需要重判,但我觉得我的算法没啥问题
首先要尽可能的缩小瓶子数目,不断除2, 但是当瓶子数目为奇数时就会剩下一瓶,这时候这瓶水就要独立出来,放入一个集合中
最后这个集合进行操作, 首先要明确, 如果你有一瓶x升的水, 这个水一定是2^n, 不会是别的数了, 如果队列中不存在另外一个x,那么就必须补充x瓶水
因为每次都是对最小的进行操作,所以最后求出来肯定是最小的
#include <cstdio>
#include <cmath>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x) memset(Arr, x, sizeof(Arr))
#define REP(i, x, n) for(int i = x; i < n; ++i)
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
int n, m, k;
int main(){
int t; scanf("%d", &t);
while(t--){
priority_queue<int, vector<int>, greater<int> > Q;
scanf("%d%d", &n, &k);
int t = 1;
while(n){
if(n & 1) Q.push(t);
n /= 2;
t <<= 1;
}
LL minx = 0;
while((int)Q.size() > k){
int x = Q.top(); Q.pop();
int y = Q.top(); Q.pop();
if(x == y){
Q.push(x + y);
}else{
minx += x;
Q.push(x + x);
Q.push(y);
}
}
printf("%lld\n", minx);
}
return 0;
}
F
Tarjan离线求出最近公共祖先, 然后求这条路径上所有线段的长度, 然后排一次序, 然后每三个相邻的数判断一下能不能形成三角形
没给时间限制, 就暴力做了, 没想到还过了。。。。
昨天学长教我这题的正确解题姿势, 线段的长度都在1到1e9内, 我们可以这样想,假设三条线段a,b,c,令a<=b=<c, 如果满足a + b > c那么一定是个三角形,那么不满足的极限条件就是a + b = c, 换一种说法,就是在区间1到1e9内选择尽量多的数,使得选择出来的任意三个数都不能组成三角形, 这样推出来的结论就是这些选择出来的数满足菲波那契数列, 然后就可以根据路径的长度进行剪枝了,最终的复杂度还是O(m + q)。学长说好像是2016年大连区域赛的一道题也是这样剪的
#include <cstdio>
#include <cmath>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x) memset(Arr, x, sizeof(Arr))
#define REP(i, x, n) for(int i = x; i < n; ++i)
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
int n, m, top;
int fa[qq], pre[qq], head[qq], plen[qq], anc[qq];
int num[qq];
int l[qq], r[qq];
bool vis[qq];
struct Edge{
int v, next, w;
}edge[qq * 2];
vector<int> q[qq], f[qq];
void Add(int u, int v, int w){
edge[top].v = v;
edge[top].w = w;
edge[top].next = head[u];
head[u] = top++;
}
void Init(){
mst(head, -1);
mst(vis, false);
mst(plen, 0);
mst(anc, 0);
top = 0;
for(int i = 0; i <= n; ++i)
q[i].clear(), f[i].clear();
}
int Find(int x){
return fa[x] == -1 ? x : fa[x] = Find(fa[x]);
}
void Union(int x, int y){
int b = Find(y);
if(x != b) fa[b] = x;
}
void Tarjan(int u, int p, int w){
fa[u] = pre[u] = -1;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].v;
if(v == p || vis[v]) continue;
Tarjan(v, u, edge[i].w);
Union(u, v);
}
vis[u] = true;
pre[u] = p;
plen[u] = w;
for(int i = 0; i < (int)q[u].size(); ++i)if(vis[q[u][i]]){
anc[f[u][i]] = Find(q[u][i]);
}
}
bool check(int c, int b, int a){
if(a + b > c && a + c > b && b + c > a) return true;
return false;
}
int main(){
int t; scanf("%d", &t);
while(t--){
Init();
scanf("%d", &n);
REP(i, 1, n){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
Add(a, b, c);
Add(b, a, c);
}
int m; scanf("%d", &m);
REP(i, 0, m){
int a, b;scanf("%d%d", &a, &b);
l[i] = a, r[i] = b;
q[a].pb(b), f[a].pb(i);
q[b].pb(a), f[b].pb(i);
}
Tarjan(1, -1, 0);
/*for(int i = 0; i < m; ++i){
printf("%d\n", anc[i]);
}*/
REP(i, 0, m){
int cnt = 0;
int u = l[i];
int v = anc[i];
while(u != v){
num[cnt++] = plen[u];
u = pre[u];
}
u = r[i];
while(u != v){
num[cnt++] = plen[u];
u = pre[u];
}
sort(num, num + cnt);
bool flag = false;
for(int j = 2; j < cnt; ++j){
if(check(num[j], num[j - 1], num[j - 2])){
flag = true;
break;
}
}
if(flag) puts("Yes");
else puts("No");
}
}
return 0;
}
/**************************************************************
Problem: 1229
User: Yokile
Language: C++
Result: Accepted
Time:104 ms
Memory:11964 kb
****************************************************************/
H
这题有个很显然的结论,你如果能凑出区间[0, x],那么对于一个数p,如果x + 1 >= p, 那么你就能凑出区间[0,x + p]的所有数
这题有个加强版的 传送门
#include <cstdio>
#include <cmath>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x) memset(Arr, x, sizeof(Arr))
#define REP(i, x, n) for(int i = x; i < n; ++i)
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
int n, m;
LL num[qq];
int main(){
int t; scanf("%d", &t);
while(t--){
scanf("%d", &n);
REP(i, 0, n){
scanf("%lld", num + i);
}
LL money = 0;
sort(num, num + n);
REP(i, 0, n){
if(num[i] <= money + 1){
money += num[i];
}else{
break;
}
}
printf("%lld\n", money);
}
return 0;
}
/**************************************************************
Problem: 1231
User: Yokile
Language: C++
Result: Accepted
Time:0 ms
Memory:0 kb
****************************************************************/