【AtCoder】AGC008
AGC008
A - Simple Calculator
如果符号相同,那么如果y比x大直接走,否则需要两次反号
如果符号不同,需要绝对值的差加一次反号
如果有一个是0,且y比x要小,那只需要一次反号
#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('\n')
#define eps 1e-10
#define MAXN 5005
//#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);
}
int64 x,y;
void Solve() {
read(x);read(y);
if(x * y >= 0) {
if(y >= x) {out(y - x);enter;}
else if(x * y != 0) {out(x - y + 2);enter;}
else {out(x - y + 1);enter;}
}
else {
out(abs(abs(x) - abs(y)) + 1);enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}
B - Contiguous Repainting
合法的序列中必须有一段长度大于等于K的同色的段即可
枚举同色段的位置和它的颜色,只需要加上两边所有的正数即可
#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('\n')
#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,K;
int64 pre[MAXN],suf[MAXN],a[MAXN],sum[MAXN];
void Solve() {
read(N);read(K);
for(int i = 1 ; i <= N ; ++i) {
read(a[i]);
sum[i] = sum[i - 1] + a[i];
pre[i] = pre[i - 1];
if(a[i] > 0) pre[i] = pre[i] + a[i];
}
for(int i = N ; i >= 1 ; --i) {
suf[i] = suf[i + 1];
if(a[i] > 0) suf[i] = suf[i] + a[i];
}
int64 ans = 0;
for(int i = 1 ; i <= N ; ++i) {
int r = i + K - 1;
if(r > N) break;
int64 all = pre[i - 1] + suf[r + 1];
if(sum[r] - sum[i - 1] > 0) all += sum[r] - sum[i - 1];
ans = max(ans,all);
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}
C - Tetromino Tiling
简单分析一下只有I,O,L,J是有用的
我们先尽量一个I,一个L,一个J拼成一个长度为6的
然后剩下的II两两组合,L两两组合,J两两组合
如果I,J,L剩下的有两个,且我拼过一个长度为6的,那么我把这个长度为6的拆开分给这两个
#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('\n')
#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);
}
int64 aI,aO,aT,aJ,aL,aS,aZ;
int64 ans = 0;
void Solve() {
read(aI);read(aO);read(aT);read(aJ);read(aL);read(aS);read(aZ);
ans = aO;
int64 t = min(aI,min(aJ,aL));
ans += 3 * t;
aI -= t;aJ -= t;aL -= t;
ans += (aI / 2) * 2;aI %= 2;
ans += (aJ / 2) * 2;aJ %= 2;
ans += (aL / 2) * 2;aL %= 2;
if(aI + aJ + aL >= 2) {
if(t) {
ans -= 3;ans += 4;
}
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}
D - K-th K
直接把这些位置排序,然后按照需要给位置最前且没有满足的位置填需要的数
然后如果一个位置过去了,我们把它后面的数,例如第2个2填完了,我们把N - 2个2扔进一个vector,vector里面的数不在乎顺序,随取随用
如果没有数用了也是不合法
#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('\n')
#define eps 1e-10
#define MAXN 505
//#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;
int x[MAXN],id[MAXN];
int val[MAXN * MAXN];
bool vis[MAXN];
vector<int> r;
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) {
read(x[i]);
val[x[i]] = i;
id[i] = i;
}
sort(id + 1,id + N + 1,[](int a,int b){return x[a] < x[b];});
int p = 1,rem = id[1] - 1;
vis[1] = 1;
for(int i = 1 ; i <= N * N ; ++i) {
if(val[i]) {
if(!vis[val[i]]) {puts("No");return;}
for(int j = 1 ; j <= N - val[i] ; ++j) r.pb(val[i]);
}
else {
while(!rem && p < N) {++p;rem = id[p] - 1;}
if(rem) {
val[i] = id[p];
--rem;
if(!rem) vis[id[p]] = 1;
}
else {
if(r.size() == 0) {puts("No");return;}
val[i] = r.back();r.pop_back();
}
}
}
puts("Yes");
for(int i = 1 ; i <= N * N ; ++i) {out(val[i]);space;}
enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}
E - Next or Nextnext
我们直接建一张i->a[i]的图,最后我们用排列i->p[i]建出的图相当于一次走一步或者一次走两步
发现这是分开的很多基环内向树,我们分开算答案统计即可
如果有一个环,环上的某些点挂着链,链必须只是单链,否则就不合法
相当于往环上放点,如果一个点上挂着链,那么这个点之前链长的边都会被这个点占据
我们把占据的都标记好了,发现这些占据不重合的时候才算合法
这个时候我们看看这个点链长+1前位置的边是否被占据,如果没有被占据,这个点挂着的链在环上就有两种填法
如果只有一个环,没有链
那么奇数的环(1除外)可以有两种走法
而且两个数量相同的环可以拼成一个新环,这个环上每个人到目标位置距离都是2
可以用一个dp来计算相同点数的环的分配方案
把这些方案都乘起来就是总方案
#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('\n')
#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);
}
const int MOD = 1000000007;
int N,head[MAXN],sumE;
int a[MAXN];
int deg[MAXN],line[MAXN];
bool vis[MAXN],mark[MAXN];
int cnt[MAXN],dp[MAXN],f[MAXN];
vector<int> v;
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
void update(int &x,int y) {
x = inc(x,y);
}
queue<int> Q;
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) {
read(a[i]);
++deg[a[i]];
}
for(int i = 1 ; i <= N ; ++i) {
if(!deg[i]) Q.push(i);
}
while(!Q.empty()) {
int u = Q.front();Q.pop();
vis[u] = 1;
if(line[a[u]]) {puts("0");return;}
line[a[u]] = line[u] + 1;
if(!(--deg[a[u]])) Q.push(a[u]);
}
int ans = 1;
for(int i = 1 ; i <= N ; ++i) {
if(!vis[i]) {
v.clear();
int p = i;v.pb(i);vis[p] = 1;p = a[p];
while(p != i) {
vis[p] = 1;
v.pb(p);
p = a[p];
}
int n = v.size();
bool no = 1;
for(int j = 0 ; j < n ; ++j) {
mark[j] = 0;
if(line[v[j]]) no = 0;
}
if(no) {cnt[n]++;continue;}
for(int j = 0 ; j < n ; ++j) {
for(int k = 0 ; k < line[v[j]] ; ++k) {
int t = ((j - k) % n + n) % n;
if(mark[t]) {puts("0");return;}
mark[t] = 1;
}
}
for(int j = 0 ; j < n ; ++j) {
if(!line[v[j]]) continue;
int t = ((j - line[v[j]]) % n + n) % n;
if(!mark[t]) ans = mul(ans,2);
}
}
}
for(int i = 1 ; i <= N ; ++i) {
if(cnt[i]) {
for(int j = 1 ; j <= cnt[i] ; ++j) dp[j] = 0;
dp[0] = 1;
for(int j = 1 ; j <= cnt[i] ; ++j) {
dp[j] = dp[j - 1];
if((i & 1) && i != 1) update(dp[j],dp[j - 1]);
if(j >= 2) {
update(dp[j],mul(j - 1,mul(i,dp[j - 2])));
}
}
ans = mul(ans,dp[cnt[i]]);
}
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}
F - Black Radius
1300分的话,如果\(f(x,d)\)即从x点延伸d长度不为全集,那么如果d可以更小,我们就不统计,也就是附近有个点\(f(y,d - 1)\)和它覆盖的是一样的
这个可以用x当根每个儿子最大深度统计出来,就是两次树dp
把这个最大的d记做\(high[x]\)
然后我们对于每个点记录一个\(low[x]\)表示最小能从哪个点往上延伸
我们在求high的时候会发现每个点和它当根的时候深度最大的那个儿子可能有一个low上的转移关系,我们记录下来
然后我们high从小到大枚举每个点,如果这个点是偏爱点,那么low是0,如果这个点low <= high,就证明这个点大于low的时候已经是偏爱点一样了,可以更新周围的点,利用我们求的转移关系然后更新周围点即可
#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('\n')
#define eps 1e-10
#define MAXN 200005
//#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);
}
struct node {
int to,next;
}E[MAXN * 2];
int N,head[MAXN],sumE,dep[MAXN],fr[MAXN],high[MAXN],low[MAXN];
char s[MAXN];
vector<int> rec[MAXN];
vector<pii > to[MAXN];
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
void dfs1(int u,int fa) {
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
dfs1(v,u);
dep[u] = max(dep[u],dep[v] + 1);
}
}
}
void dfs2(int u,int fa) {
vector<pii > vec;
dep[u] = max(dep[u],fr[u] + 1);
vec.pb(mp(1,u));
if(fa) vec.pb(mp(fr[u] + 2,fa));
pii p = mp(0,0);
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
vec.pb(mp(dep[v] + 2,v));
if(dep[v] > dep[p.se]) p.se = v;
if(dep[p.se] > dep[p.fi]) swap(p.fi,p.se);
}
}
sort(vec.begin(),vec.end());
high[u] = dep[u] - 1;
int s = vec.size() - 1;
high[u] = min(high[u],vec[s - 1].fi);
if(high[u] < dep[u] - 1){
to[u].pb(mp(vec[s].se,high[u]));
}
vec.clear();
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
fr[v] = max(fr[v],fr[u] + 1);
if(v != p.fi) fr[v] = max(fr[v],dep[p.fi] + 1);
if(v != p.se) fr[v] = max(fr[v],dep[p.se] + 1);
}
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
dfs2(v,u);
}
}
}
void Solve() {
read(N);
int a,b;
for(int i = 1 ; i < N ; ++i) {
read(a);read(b);add(a,b);add(b,a);
}
scanf("%s",s + 1);
dep[0] = -1;fr[1] = -1;
dfs1(1,0);dfs2(1,0);
for(int i = 1 ; i <= N ; ++i) {
rec[high[i]].pb(i);
low[i] = high[i] + 1;
}
for(int i = 0 ; i <= N ; ++i) {
for(auto v : rec[i]) {
if(s[v] == '1') {
low[v] = 0;
}
if(low[v] <= high[v]){
for(auto k : to[v]) {
low[k.fi] = min(low[k.fi],k.se);
}
}
}
}
int64 ans = 1;
for(int i = 1 ; i <= N ; ++i) {
ans += high[i] - low[i] + 1;
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;