题目 | A | B | C | D | E | F | G |
---|---|---|---|---|---|---|---|
场上成绩 | AC | AC | AC | WA | |||
场后成绩 | AC | AC | AC | AC | AC | AC | AC |
是否看题解 | N | N | N | N | Y | N | Y |
说在前面
草,E题挂了,没开long long。
A
如果((a_i,a_{i + 1}))不满足,那么(a_i leftarrow 2 cdot a_i)。
# include <bits/stdc++.h>
using namespace std;
const int N = 100;
int t;
int n;
int a[N];
int dfs(int l,int r)
{
// printf("l = %d,r = %d
",min(l,r),max(l,r));
if(double(max(l,r)) / double(min(l,r)) <= 2.0)
{
return 0;
}
int mid = min(2 * min(l,r),max(l,r));
int s = dfs(l,mid) + dfs(r,mid) + 1;
// printf("l = %d, r = %d, s = %d,mid = %d
",l,r,s,mid);
return s;
}
int main(void)
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
}
int total = 0;
for(int i = 1; i < n; i++)
{
total += dfs(a[i],a[i + 1]);
}
printf("%d
",total);
}
return 0;
}
B
求出现在的(c_0',c_1',c_2'),分类讨论:
- 如果都相等,不用改
- 如果$ > frac{n}{3}$的有一个,就分给另外两个、
- 如果$ > frac{n}{3}$的有两个,就分给另外一个。
# include <bits/stdc++.h>
using namespace std;
const int N = 3e4 + 5;
int n,t;
int a[N];
map<int,map<int,int> > dp;
int c[3];
int delta[3];
int Get(int i,int j)
{
if(i == j) return 0;
if(i == 0 && j == 1) return 1;
if(i == 0 && j == 2) return 2;
if(i == 1 && j == 2) return 1;
if(i == 1 && j == 0) return 2;
if(i == 2 && j == 0) return 1;
if(i == 2 && j == 1) return 2;
}
int main(void)
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(c,0,sizeof(c));
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
a[i] = a[i] % 3;
++c[a[i]];
}
int Begin = n / 3;
vector <int> C,D;
for(int i = 0; i <= 2; i++)
{
delta[i] = c[i] - Begin;
if(delta[i] < 0) C.push_back(i);
else if(delta[i] > 0) D.push_back(i);
}
int ans = 0;
if(D.size() == 0)
{
printf("0
");
continue;
}
else
{
if(D.size() == 1)
{
for(int i = 0; i < (int)C.size(); i++)
{
int v = C[i];
ans += (-delta[v]) * Get(D[0],v);
}
}
else
{
//Give C[0]
ans += (delta[D[0]]) * Get(D[0],C[0]) + (delta[D[1]]) * Get(D[1],C[0]);
}
}
printf("%d
",ans);
}
return 0;
}
C
暴力枚举(a),然后(b = sqrt[3]{x - a^3}),判断一下有没有整数解,我这里用的二分,(mathcal{O}(sqrt[3]{n}log{sqrt[3]{n}}))
# include <bits/stdc++.h>
using namespace std;
# define int long long
int t;
long long x;
long long qfind(long long x,int i)
{
long long ans = 0;
long long l = 1, r = i;
while(l <= r)
{
int mid = (l + r) >> 1;
if(mid * mid * mid == x)
{
return ans = mid;
}
else
{
if(mid * mid * mid > x) r = mid - 1;
else l = mid + 1;
}
}
return ans;
}
bool check(void)
{
for(long long i = 1; i * i * i <= x; i++)
{
long long s = qfind(x - i * i * i,i);
if(s)
{
return 1;
}
}
return 0;
}
signed main(void)
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&x);
printf("%s
",check() ? "YES" : "NO");
}
return 0;
}
D
根据题意暴力模拟,最大值位置用ST表。单组询问(mathcal{O}(nlog{n} + n))
# include <bits/stdc++.h>
using namespace std;
const int N = 105;
int t,n;
vector <int> g[N];
int a[N];
int ST[N][15];
int Log[N];
int id[N];
int root = 0;
void RMQ1(void)
{
for(int i = 1; i <= n; i++)
{
ST[i][0] = a[i];
}
for(int j = 1; (1 << j) <= n; j++)
{
for(int i = 1; i + (1 << j) - 1 <= n; i++)
{
ST[i][j] = max(ST[i][j - 1],ST[i + (1 << (j - 1))][j - 1]);
}
}
}
int Get(int l,int r)
{
int mid = Log[r - l + 1];
return max(ST[l][mid],ST[r - (1 << mid) + 1][mid]);
}
int build(int l,int r) // return : root
{
if(l == r)
{
return l;
}
int maxi = id[Get(l,r)];
int L = 0,R = 0;
if(l <= maxi - 1) L = build(l,maxi - 1);
if(maxi + 1 <= r) R = build(maxi + 1,r);
if(L)
{
g[maxi].push_back(L);
g[L].push_back(maxi);
}
if(R)
{
g[maxi].push_back(R);
g[R].push_back(maxi);
}
return maxi;
}
int dep[N];
void dfs(int x,int fa)
{
for(int i = 0; i < (int)g[x].size(); i++)
{
int v = g[x][i];
if(v == fa) continue;
dep[v] = dep[x] + 1;
dfs(v,x);
}
return;
}
int main(void)
{
scanf("%d",&t);
Log[2] = 1;
for(int i = 3; i <= 100; i++) Log[i] = Log[i / 2] + 1;
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
id[a[i]] = i;
}
RMQ1();
for(int i = 1; i <= n; i++)g[i].clear();
root = build(1,n);
dep[root] = 0;
dfs(root,0);
for(int i = 1; i <= n; i++)
{
printf("%d ",dep[i]);
}
putchar('
');
}
return 0;
}
E
排个序,如果第(i)个选手是有几率赢的,考虑最优状况,每次都遇到当前最小的值,如果累计的值小于当前最小,那么这个就不行,否则行。
那么枚举每个数,并且模拟,(mathcal{O}(n^2))
这样显然过不去。
然后我们想到:
在排序后,如果第(i)个行,那么它后面的都行。
那么我们考虑枚举这个最小的行的值,(mathcal{O}(nlog{n}))。
# include <bits/stdc++.h>
using namespace std;
# define int long long
const int N = 2e5 + 5;
int t,n;
struct node
{
int soc;
int x;
}a[N];
bool flag[N];
bool compare(const struct node &x,const struct node &y) {return x.x < y.x;}
bool check(int x)
{
int tot = a[x].x;
for(int i = 1; i <= n; i++)
{
if(i == x) continue;
if(a[i].x <= tot) tot += a[i].x;
else return false;
}
return true;
}
int qfind(void)
{
int l = 1,r = n;
int ans = n;
while(l <= r)
{
int mid = (l + r) >> 1;
if(check(mid))
{
r = mid - 1;
ans = mid;
}
else l = mid + 1;
}
return ans;
}
signed main(void)
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
memset(flag,0,sizeof(flag));
for(int i = 1; i <= n; i++)
{
scanf("%lld",&a[i].x);
a[i].soc = i;
// flag[i] = 0;
}
sort(a + 1,a + n + 1,compare);
// int total = 0;
int tot = 0;
int C = qfind();
for(int i = C; i <= n; i++)
{
flag[a[i].soc] = 1;
++tot;
}
printf("%lld
",tot);
for(int i = 1; i <= n; i++)
{
if(flag[i])
{
printf("%lld ",i);
}
}
putchar('
');
}
return 0;
}
F
考虑将每个数的出现的次数求出来,但是(a_i le 10^9),就得离散化一下,设其为(c_i)。
对(c)排序,枚举(C),对于每个(c_i),如果(c_i < C),就得消到(0),如果(c_i > C),就得消到(C)
答案即为
整个前缀和。(mathcal{O}(nlog{n}))
# include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int t,n;
int a[N],b[N],c[N];
long long q[N];
int qfind(int C)
{
int l = 1, r = n;
int ans = n;
while(l <= r)
{
int mid = (l + r) >> 1;
if(c[mid] < C)
{
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
return ans;
}
int main(void)
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++) c[i] = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b + 1, b + n + 1);
int Len = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n; i++)
{
a[i] = lower_bound(b + 1, b + Len + 1, a[i]) - b;
++c[a[i]];
}
// sort(a + 1, a + n + 1);
sort(c + 1, c + n + 1);
bool flag = 1;
for(int i = 1; i < n; i++)
{
if(c[i] != c[i + 1])
{
flag = 0;
break;
}
}
if(flag)
{
printf("0
");
continue;
}
q[0] = 0;
for(int i = 1; i <= n; i++)
{
q[i] = q[i - 1] + c[i];
}
int ans = n;
for(int C = 0; C <= n; C++)
{
int w = qfind(C);
int ANS = 0;
ANS = q[w];
ANS = ANS + q[n] - q[w];
ANS = ANS - (n - w) * C;
ans = min(ans,ANS);
}
printf("%d
",ans);
}
return 0;
}
G
设(q_i = sum_{j = 1} ^ i a_j,Max_i = max_{j = 1} ^ i {q_j})。
显而易见: 如果(Max_n < x)且(q_x le 0),输出(-1)。
显而易见: (r = left lceil dfrac{x - Max_n}{q_n} ight ceil),其中(r)为对于询问(x)的整圈数。
证明: 最小化(r cdot q_n + Max_n ge x (r in mathbb{N_+})),显然取(r = left lceil dfrac{x - Max_n}{q_n} ight ceil)
如果还有残圈就在(Max)里二分就行,(Max)显然具有单调性,即(Max_i ge Max_{i - 1}(1 < i le n))。
# include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int t,n,m;
long long a[N];
long long x[N];
long long q[N],Max[N];
int main(void)
{
// freopen("G.out","w",stdout);
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%lld",&a[i]);
}
for(int i = 0; i <= n; i++) Max[i] = -1e12;
for(int i = 1; i <= n; i++)
{
q[i] = q[i - 1] + a[i];
Max[i] = max(Max[i - 1],q[i]);
}
for(int i = 1; i <= m; i++)
{
scanf("%lld",&x[i]);
if(Max[n] < x[i] && q[n] <= 0)
{
printf("-1 ");
continue;
}
long long r = 0;
if(Max[n] < x[i])
{
r = ceil(double(x[i] - Max[n]) / double(q[n]));
x[i] -= r * q[n];
}
int j = lower_bound(Max + 1, Max + n + 1, x[i]) - Max;
printf("%lld ",r * n + j - 1);
}
putchar('
');
}
return 0;
}