AGC011
A - Airport Bus
大意:有N个人,每个人只能在([T_i,T_i +K])这段区间乘车,每辆车安排C人,问最少安排几辆车
直接扫,遇到一个没有车的在(T_i +K)分配一辆
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('
')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 500005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 - '0' + c;
c = getchar();
}
res = res * f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
int N,C,K;
int T[1000005];
void Solve() {
read(N);read(C);read(K);
for(int i = 1 ; i <= N ; ++i) read(T[i]);
sort(T + 1,T + N + 1);
int ans = 0;
int cnt = 0,t = 0;
for(int i = 1 ; i <= N ; ++i) {
if(t < T[i] || !cnt) {
++ans;
t = T[i] + K;
cnt = C;
}
--cnt;
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
B - Colorful Creatures
大意:N个怪兽颜色两两不同,两个怪物如果一个大小是A颜色是B,一个大小是C(C <= 2 * A)颜色是D,新怪物可以是大小A+C,颜色是B,问最后可能是几种颜色
直接二分找满足要求的数的位置,然后能扩到的最大体积就是从最小的数到这个数的前缀和,每次至少扩大两倍,所以只用log次
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('
')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 500005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 - '0' + c;
c = getchar();
}
res = res * f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
int N;
int64 A[100005],tmp[100005],sum[1000005];
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) {
read(A[i]);
tmp[i] = A[i];
}
tmp[N + 1] = 1000000001;
sort(tmp + 1,tmp + N + 2);
int ans = 0;
for(int i = 1 ; i <= N ; ++i) {
sum[i] = sum[i - 1] + tmp[i];
}
for(int i = 1 ; i <= N ; ++i) {
if(2 * A[i] >= tmp[N]) {++ans;continue;}
int t = lower_bound(tmp + 1,tmp + N + 2,2 * A[i] + 1) - tmp - 1;
while(1) {
if(2 * sum[t] >= tmp[N]) {++ans;break;}
int p = lower_bound(tmp + 1,tmp + N + 2,sum[t] * 2 + 1) - tmp - 1;
if(p == t) break;
t = p;
}
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
C - Squared Graph
大意是给出一张图,然后建一张新图,新图的点标号是(a,b)
如果a和c有一条边,b和d有一条边,那么(a,b)和(c,d)之间有一条边
我们把这道题当成这道题来做,给出两张图,如果第一张图有边(a,c),第二张图有边(b,d),那么第三张图上有边(a,b)(c,d)
如果某张图只有一个点,那么答案就是另一张图的点数
然后我们发现对于某两个点对第一张图(a,c),第二张图(b,d)如果有一条长度为L的路径,那么第三张图(a,b)(c,d)一定可以联通
但是我们发现我们经过的路径可以不是简单路径,也就是我们反复走一条边,那么我们只和路径长度的奇偶性有关了
很容易想到二分图,如果两张图都是二分图且联通的话,那么第三张图联通分量的个数是2
分别是(S_a * T_b cup T_a * S_b)和(S_a * S_b cup T_a * T_b)
而两张图都是非二分图且联通的话,任意路径的奇偶性都可以互相转化,所以整张图就是一个联通块
那么我们求出两个图的孤立点个数(i_A,i_B),两个图的非二分图联通块个数(p_A,p_B),两个图的二分图联通块个数(q_A,q_B)
答案就是
(i_Ai_B + i_A(N_B - i_B) + i_B(N_A - i_A) + p_Ap_B + p_Aq_B + p_Bq_A + 2q_Aq_B)
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('
')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 - '0' + c;
c = getchar();
}
res = res * f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
int N,M,I,P,Q;
struct node {
int next,to;
}E[MAXN * 2];
int head[MAXN],sumE,col[MAXN];
bool vis[MAXN];
void dfs(int u) {
vis[u] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) {
dfs(v);
}
}
}
bool paint(int u) {
if(!col[u]) col[u] = 2;
for(int i = head[u] ; i; i = E[i].next) {
int v = E[i].to;
if(!col[v]) {col[v] = col[u] ^ 1;if(!paint(v)) return false;}
else if(col[v] == col[u]) return false;
}
return true;
}
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
void Solve() {
read(N);read(M);
int u,v;
for(int i = 1 ; i <= M ; ++i) {
read(u);read(v);
add(u,v);add(v,u);
}
for(int i = 1 ; i <= N ; ++i) {
if(!head[i]) ++I;
else if(!vis[i]){
dfs(i);
if(paint(i)) ++Q;
else ++P;
}
}
int64 ans = 1LL * I * I + 2LL * I * (N - I);
ans += 1LL * P * P + 2LL * P * Q + 2LL * Q * Q;
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
D - Half Reflector
大意是n个管子排成一排,每个管子有两种状态,A状态是从某个方向进去,从原方向出来,B状态是从某个方向进去,从另一个方向出来
球经过一个A状态的管子这个管子会立刻变成B状态,经过一个B状态的管子会立刻变成A状态
往里面扔K个球,问最后管子的状态
我们发现如果第一个管子是A的话,球会立刻弹出去
否则的话
如果第二个管子是B
那么
A -> B
A A ->
如果第二个管子是A
A -> A
A <- B
B -> B
B A ->
也就是,每次操作后的状态只与右边第一个管子有关,并且最后一个管子一定是A
那么操作可以考虑成,删掉第一个字符,后面的字符全部取反,然后再最后填上一个A
然而有K次,我们发现起点移动N次之后就是循环了
如果N次之后是
BABABA...那么这个形态不会变
如果N次之后是
ABABAB...
那么之后的形态就是
BBABAB...
ABABAB...
这样的循环了
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('
')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 - '0' + c;
c = getchar();
}
res = res * f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
char s[MAXN];
int N,K,p = 1,num[MAXN],cnt,st;
void Solve() {
read(N);read(K);
scanf("%s",s + 1);
for(int i = 1 ; i <= N ; ++i) num[i] = s[i] - 'A';
st = num[1];
while(K--) {
if(st == 0) {st ^= 1;num[p] ^= 1;}
else {
++p;++cnt;
st = num[p];
st ^= (cnt & 1);
}
if(p > N) break;
}
if(p <= N) {
for(int i = p ; i <= N ; ++i) putchar('A' + (num[i] ^ (cnt & 1)));
int t = N - (N - p + 1),c = (cnt - 1) & 1;
while(t--) {
putchar('A' + c);
c ^= 1;
}
}
else {
if((cnt - 1) & 1) {
for(int i = 1 ; i <= N ; ++i) putchar('A' + (i & 1));
}
else {
putchar('A' + (K & 1));
for(int i = 1 ; i < N ; ++i) putchar('A' + (i & 1));
}
}
enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
E - Increasing Numbers
我们发现一个非下降的数字一定可以用不超过九个1111111111...1111表示
那么我们可以得到这样的一个式子,假如我们用了k个数,那么最多的话可以是这样的
(N = sum_{i = 1}^{9k} (10^{r_i} - 1) / 9)
(9N + 9k = sum_{i = 1}^{9k} 10^{r_{i}})
我们只要每次计算出9N + 9 ,9N + 18...,然后看看十进制下每一位的数字和有没有超过9k,直接加的话最坏情况是一次操作(O(L))的,但是大家应该都有种直觉总的操作就是(O(L))的……就是势能分析啦,不太会证,就是一次长的进位过后之后不会再进位了。。。
复杂度(O(lg N))
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('
')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 - '0' + c;
c = getchar();
}
res = res * f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
struct Bignum {
vector<int> v;
int sum;
Bignum operator = (string s) {
v.clear();
sum = 0;
for(int i = s.length() - 1 ; i >= 0 ; --i) {
v.pb(s[i] - '0');
sum += s[i] - '0';
}
return *this;
}
friend Bignum operator * (const Bignum &a,const int b) {
int s = a.v.size();
Bignum c;c.v.clear();
for(int i = 0 ; i <= s ; ++i) c.v.pb(0);
int g = 0;
for(int i = 0 ; i < s ; ++i) {
int x = a.v[i] * b + g;
c.v[i] = x % 10;
g = x / 10;
}
if(g) c.v[s] = g;
for(int i = s ; i > 0 ; --i) {
if(c.v[i] == 0) c.v.pop_back();
else break;
}
c.sum = 0;s = c.v.size();
for(int i = 0 ; i < s ; ++i) c.sum += c.v[i];
return c;
}
}A;
string s;
void Solve() {
cin>>s;
A = s;
A = A * 9;
int ans = 0;
while(1) {
int s = A.v.size();
int g = 9;
for(int i = 0 ; i < s ; ++i) {
if(!g) break;
A.sum -= A.v[i];
int x = A.v[i] + g;
A.v[i] = x % 10;
A.sum += A.v[i];
g = x / 10;
}
if(g) A.v.pb(g),A.sum += g;
++ans;
if(ans * 9 >= A.sum) break;
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
F - Train Service Planning
如果认为从0到N每一站休息时间是(q_0,q_1,q_2...q_{N- 1})
然后我们认为从N到0每一站休息时间是(p_0,p_1,p_2...p_{N - 1})
((sum_{i = 0}^{s - 1} q_i + sum_{i = 0}^{s - 1}A_{i},sum_{i = 0}^{s - 1} q_i + sum_{i = 0}^{s}A_{i}))
这是从第s - 1站走到第s站的时间段
((N - sum_{i = 0}^{s - 1} p_i - sum_{i = 0}^{s}A_{i},N - sum_{i = 0}^{s - 1} p_i - sum_{i = 0}^{s - 1}A_{i}))
我们要这两个区间没有交集
由于取模k意义下,最后只要满足
(sum_{i = 0}^{s - 1}p_{i} + q_i otin (-2sum_{i = 0}^{s}A_{i},-2sum_{i = 0}^{s - 1}A{i}))
最后就变成,对于每个单行道,我们要求坐标取模的值在某个区间内
设(dpL[i])是i的时候在(L[i])的位置上之后还要走多远,(dpR[i])同理
从后往前更新,每次找(L[i])不在区间([L[j],R[j]])的一个最小的j
然后用(dpL[j])和(dpR[j])更新
线段树优化
然后可以当答案的(dpL[i])要求(L[i])在(1-i)的区间内,可以用线段树求
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('
')
#define eps 1e-10
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 +c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N;
int64 K,A[MAXN],sum[MAXN];
int B[MAXN],tot;
int64 L[MAXN],R[MAXN],dpL[MAXN],dpR[MAXN],val[MAXN];
struct node {
int l,r;
int mx,lz;
}tr[MAXN * 4];
int id;
void update(int u) {
if(!id) tr[u].mx = min(tr[u << 1].mx,tr[u << 1 | 1].mx);
else tr[u].mx = max(tr[u << 1].mx,tr[u << 1 | 1].mx);
}
void addlz(int u,int v) {
tr[u].lz = v;
tr[u].mx = v;
}
void pushdown(int u) {
if(tr[u].lz) {
addlz(u << 1,tr[u].lz);
addlz(u << 1 | 1,tr[u].lz);
tr[u].lz = 0;
}
}
void build(int u,int l,int r,int v) {
tr[u].l = l;tr[u].r = r;tr[u].lz = 0;
if(l == r) {
tr[u].mx = v;
return;
}
int mid = (l + r) >> 1;
build(u << 1,l,mid,v);
build(u << 1 | 1,mid + 1,r,v);
update(u);
}
void cover(int u,int l,int r,int v) {
if(l > r) return;
if(tr[u].l == l && tr[u].r == r) {
addlz(u,v);
return;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(r <= mid) cover(u << 1,l,r,v);
else if(l > mid) cover(u << 1 | 1,l,r,v);
else {cover(u << 1,l,mid,v);cover(u << 1 | 1,mid + 1,r,v);}
update(u);
}
int query(int u,int l,int r) {
if(l > r) return N + 1;
if(tr[u].l == l && tr[u].r == r) return tr[u].mx;
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(r <= mid) return query(u << 1,l,r);
else if(l > mid) return query(u << 1 | 1,l,r);
else {
if(!id) return min(query(u << 1,l,mid),query(u << 1 | 1,mid + 1,r));
else return max(query(u << 1,l,mid),query(u << 1 | 1,mid + 1,r));
}
}
int64 dist(int64 A,int64 B) {
if(B >= A) return B - A;
else return K - (A - B);
}
void Solve() {
read(N);read(K);
for(int i = 1 ; i <= N ; ++i) {
read(A[i]);read(B[i]);
sum[i] = sum[i - 1] + A[i];
if(B[i] == 1) {
if(2 * A[i] > K) {puts("-1");return;}
L[i] = (-2 * sum[i - 1] % K + K) % K;
R[i] = (-2 * sum[i] % K + K) % K;
val[++tot] = L[i];val[++tot] = R[i];
}
}
sort(val + 1,val + tot + 1);
tot = unique(val + 1,val + tot + 1) - val - 1;
id = 0;
build(1,1,tot,N + 1);
for(int i = N ; i >= 1 ; --i) {
if(B[i] == 1) {
int l = lower_bound(val + 1,val + tot + 1,L[i]) - val;
int r = lower_bound(val + 1,val + tot + 1,R[i]) - val;
int t = query(1,l,l);
if(t == N + 1) dpL[i] = 0;
else dpL[i] = min(dpL[t] + dist(L[i],L[t]),dpR[t] + dist(L[i],R[t]));
t = query(1,r,r);
if(t == N + 1) dpR[i] = 0;
else dpR[i] = min(dpR[t] + dist(R[i],R[t]),dpL[t] + dist(R[i],L[t]));
if(l <= r) {cover(1,1,l - 1,i);cover(1,r + 1,tot,i);}
else {cover(1,r + 1,l - 1,i);}
}
}
id = 1;
build(1,1,tot,0);
int64 ans = 1e18;
for(int i = 1 ; i <= N ; ++i) {
if(B[i] == 1) {
int l = lower_bound(val + 1,val + tot + 1,L[i]) - val;
int r = lower_bound(val + 1,val + tot + 1,R[i]) - val;
int t = query(1,l,l);
if(t == 0) ans = min(ans,dpL[i]);
t = query(1,r,r);
if(t == 0) ans = min(ans,dpR[i]);
if(l <= r) {cover(1,1,l - 1,i);cover(1,r + 1,tot,i);}
else {cover(1,r + 1,l - 1,i);}
}
}
ans += 2 * sum[N];
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}