A - Two Integers

如果\(X\)是\(Y\)的倍数的话不存在

可以输出\(X \cdot (\frac{Y}{gcd(X,Y)} - 1)\)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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;
int64 gcd(int64 a,int64 b) {
return b == 0 ? a : gcd(b,a % b);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
read(X);read(Y);
if(X % Y == 0) {puts("-1");return 0;}
int64 t = Y / gcd(X,Y);
out(X * (t - 1));enter;
}

B - Two Arrays

a<b的话,这个位置一定会合法,如果a > b的话不可能再小于b了,所以我们看看在用所有位置的a增加不超过b的位置的情况下,能一共给b增加多少,如果这个增加数大于所有a > b的a和b差值的和就合法

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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 a[MAXN],b[MAXN],N;
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
read(N);
for(int i = 1 ; i <= N ; ++i) read(a[i]);
for(int i = 1 ; i <= N ; ++i) read(b[i]);
int64 all = 0;
for(int i = 1 ; i <= N ; ++i) {
if(a[i] > b[i]) all += a[i] - b[i];
else all -= (b[i] - a[i]) / 2;
}
if(all > 0) puts("No");
else puts("Yes");
}

C - Vacant Seat

二分

我知道了最左和最右两边的后,如果这个位置和两边都是奇数区间的话

例如

1 *** 0 *** 0

那么空位在左边

如果两边都是偶数长的话

例如

1 **** 0 **** 0

那么空位在右边

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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 num[2];
char s[15];
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
read(N);
out(0);enter;fflush(stdout);
scanf("%s",s + 1); if(s[1] == 'F') num[0] = 1;
else if(s[1] == 'M') num[0] = 0;
else return 0;
out(N - 1);enter;fflush(stdout);
scanf("%s",s + 1); if(s[1] == 'F') num[1] = 1;
else if(s[1] == 'M') num[1] = 0;
else return 0;
int L = 1,R = N - 2;
while(L < R) {
int mid = (L + R) >> 1;
out(mid);enter;fflush(stdout);
scanf("%s",s + 1); if(s[1] == 'V') return 0;
int a;
if(s[1] == 'M') a = 0;
else a = 1;
int t = a ^ ((mid - L) & 1);
if(t == num[0]) {R = mid - 1;num[1] = a;}
else {L = mid + 1;num[0] = a;}
}
out(L);enter;fflush(stdout);scanf("%s",s + 1);
return 0;
}

D - Forest

把每个点排序,如果加进来的点所在的联通块没有点,那么把这个点放进队列里,如果还有别的联通块里的点,就把这个点和别的联通块连一条边,然后删掉这个点,把这两个联通块用并查集连在一起

如果没有别的联通块里的点,那么就把这个点扔进队列,把队列打上标记,如果之后还有别的联通块的点来,然后取出队列里这个联通块中的点和新加的点连一条边

直到队列里只有一个点就把标记删除

如果只有两个联通块,队列没有标记,且有多于两个点,这两个点之间连一条边退出就好了

保证每次都是取了最小的两个点连边(第一种操作也是保证取了最小的因为我保证了在队列里同联通块的点一定会被用,所以这个点也可用)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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,M,id[MAXN],conn;
int64 a[MAXN];
int fa[MAXN];
bool vis[MAXN];
int que[MAXN],ql,qr;
bool flag = 0;
bool cmp(int s,int t) {
return a[s] < a[t];
}
int getfa(int x) {
return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
void Solve() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) {read(a[i]);id[i] = i;}
sort(id + 1,id + N + 1,cmp);
for(int i = 1 ; i <= N ; ++i) fa[i] = i;
int x,y;
conn = N;
for(int i = 1 ; i <= M ; ++i) {
read(x);read(y);
++x;++y;
conn--;
fa[getfa(x)] = getfa(y);
}
if(conn == 1) {puts("0");return;}
ql = 1,qr = 0;
int64 ans = 0;
for(int i = 1 ; i <= N ; ++i) {
int u = id[i];
if(flag) {
if(getfa(u) == getfa(que[ql])) que[++qr] = u;
else {
ans += a[que[ql]] + a[u];
--conn;
fa[getfa(u)] = getfa(que[ql]);
ql++;
if(qr == ql) flag = 0;
}
}
else {
if(vis[getfa(u)]) {
if(ql == qr) {flag = 1;que[++qr] = u;}
else if(getfa(que[ql]) == getfa(u)) {
ans += a[que[ql]] + a[que[ql + 1]];
--conn;
fa[getfa(que[ql + 1])] = getfa(que[ql]);
ql += 2;
que[++qr] = u;
}
else {
ans += a[u] + a[que[ql]];
--conn;
fa[getfa(que[ql])] = getfa(u);
ql++;
} }
else {
que[++qr] = u;vis[getfa(u)] = 1;
}
}
if(conn == 1) break;
if(conn == 2 && qr - ql + 1 >= 2 && !flag) {
ans += a[que[ql]] + a[que[ql + 1]];
--conn;
break;
}
}
if(conn != 1) {puts("Impossible");}
else {out(ans);enter;}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}

E - Antennas on Tree

简单的树dp

设\(dp[v]\)为以0为根时\(v\)点子树里最少需要选择的点

\(dp[u] = \sum_{v\in son(u)} dp[v]\)

计算一个\(cnt\)为\(v\)中\(dp[v]\)不为0的个数

$dp[u] += max(0,son - 1 - cnt) $

然后就是换根了,不难换具体看代码吧

题解

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define MAXN 100005
#define mo 974711
//#define ivorysi
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 + 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 head[MAXN],sumE,N,ans;
int dp[MAXN],fr[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) {
int son = 0,cnt = 0;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
++son;
dfs1(v,u);
if(dp[v]) ++cnt;
dp[u] += dp[v];
}
}
if(cnt < son - 1) dp[u] += son - 1 - cnt;
}
void dfs2(int u,int fa) {
int sum = 0,son = 0,cnt = 0;
if(fa != -1) {
sum = 0,son = 0,cnt = 0;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
++son;
sum += dp[v];
if(dp[v]) ++cnt;
}
}
++son;sum += fr[u];if(fr[u]) ++cnt;
if(cnt < son - 1) sum += son - 1 - cnt;
ans = min(ans,sum + 1);
}
sum = 0,son = 0,cnt = 0;
if(fa != -1) {sum += fr[u];++son;if(fr[u]) ++cnt;}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
++son;
sum += dp[v];
if(dp[v]) ++cnt;
}
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
int t = dp[v] > 0;
fr[v] = sum - dp[v];
if(son - 2 > cnt - t) fr[v] += son - 2 - cnt + t;
dfs2(v,u);
}
}
}
void Solve() {
int x,y;
read(N);
for(int i = 1 ; i < N ; ++i) {
read(x);read(y);
add(x,y);add(y,x);
}
dfs1(0,-1);
ans = dp[0] + 1;
dfs2(0,-1);
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

F - XOR Tree

如果你很熟练,你可以想到给一条路径加异或就相当于给两个端点到根加异或

我们从底到根算出每个点都需要加多少异或,然后给相同的异或值两两配对,这个时候会有单出来的

例如

1 2 3

我们可以2次解决而不是3次

我们设\(f[S]\)为\(S\)集合中的点所需要最少的操作次数,\(S\)里的异或值为0时,初始值是\(S\)中1的个数-1,否则为\(S\)中1的个数

然后用子集枚举计算,复杂度是\(3^15\)的

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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;
struct node {
int to,next,val;
}E[MAXN * 2];
int head[MAXN],sumE;
int C[MAXN],cnt[25],f[(1 << 15) + 5],siz[MAXN];
void add(int u,int v,int c) {
E[++sumE].to = v;
E[sumE].next = head[u];
E[sumE].val = c;
head[u] = sumE;
}
void dfs(int u,int fa) {
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
C[v] ^= E[i].val;
dfs(v,u);
siz[u] ^= siz[v];
}
}
C[u] ^= siz[u];
siz[u] ^= C[u];
}
void Solve() {
read(N);
int x,y,a;
for(int i = 1 ; i < N ; ++i) {
read(x);read(y);read(a);
add(x,y,a);add(y,x,a);
}
dfs(0,-1);
for(int i = 1 ; i < N ; ++i) {
cnt[C[i]]++;
}
int ans = 0,q = 0;
for(int i = 1 ; i <= 15 ; ++i) {
ans += cnt[i] / 2;
cnt[i] %= 2;
if(cnt[i]) q |= 1 << (i - 1);
}
for(int i = 1 ; i < (1 << 15) ; ++i) {
int a = 0,c = 0;
for(int j = 1 ; j <= 15 ; ++j) {
if(i >> (j - 1) & 1) {
a ^= j;
++c;
}
}
if(!a) f[i] = c - 1;
else f[i] = c;
}
for(int S = 1 ; S < (1 << 15) ; ++S) {
for(int T = (S - 1) & S ; T ; T = (T - 1) & S) {
f[S] = min(f[S],f[T] + f[S ^ T]);
}
}
ans += f[q];
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}

G - Colorful Doors

在很久以前的NOI集训……我曾经见过这题……然后成功爆0

现在我还是看不懂orz

分类讨论大题真是

我们把首尾的两个门连起来,相当于一个环

考虑全覆盖的情况,如果N是偶数

我们可以

1 2 1 2 3 4 3 4这么覆盖

如果N是奇数,由于1的时候有两个环之后N每+1环个数的奇偶性改变,我们总到不了一个环的时候,所以无解

然后我们如果有一个串010110111

我们在前面加上一个1

变成1010110111

我们统计一下两边都是1的门的个数,记为sum

如果sum 是奇数,显然不存在,因为两边都是1的门要两两配对

如果sum是4的倍数,我们把两端连续的1最后一个和第一个写成同样字母,可以变成全部覆盖且N为偶数的情况

如果sum是偶数

那么如果这些两边都是1的门是连到一起的,就相当于N是奇数的情况

如果两边都是1的门至少有两段分开的,我们就可以

1->2->3 4->5->6把2和5变成一种颜色,然后就变成了1->25->6->4->52->3这样的链

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define MAXN 200005
#define mo 974711
//#define ivorysi
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 + 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,ans[MAXN],tot,t[MAXN],to[MAXN];
char s[MAXN];
vector<int> f;
bool vis[MAXN];
void Solve() {
read(N);
scanf("%s",s + 2);
s[1] = '1';
int cnt = 0;
for(int i = 1 ; i < 2 * N ; ++i) {
if(s[i] == '1' && s[i + 1] == '1') {++cnt;t[i] = 1;}
}
if(s[2 * N] == '1') {++cnt;t[2 * N] = 1;}
if(cnt & 1) {puts("No");return;}
bool flag = 0;
if(cnt % 4 != 0) {
int a = 1,b = 2 * N;
int c = 0;
while(t[a] == 1 && a <= 2 * N) ++a;
--a; while(t[b] == 1 && b >= 1) --b;
++b;
if(a > b) {puts("No");return;}
if(a >= 1 || b <= 2 * N) ++c;
for(int i = a + 1 ; i <= b - 1 ; ++i) {
if(t[i] == 1 && t[i - 1] != 1) ++c;
}
if(c < 2) {puts("No");return;}
if(c == 2 && a < 1 && b <= 2 * N) flag = 1;
}
puts("Yes");
if(flag) {
f.clear();
int ano;
for(int i = 1 ; i <= 2 * N ; ++i) {
if(t[i] == 1) {
ans[i] = ++tot;ans[2 * N] = tot;
ano = i;
break;
}
}
int p = 2 * N;
while(t[p] == 1) --p;
ans[p] = ++tot;ans[1] = tot;
for(int i = p + 1 ; i < 2 * N ; ++i) f.pb(i);
p = ano;
while(t[p] == 1) ++p;
for(int i = ano + 1 ; i < p ; ++i) f.pb(i);
while(1) {
int h = p;
while(s[h + 1] == '0') ++h;
if(ans[h]) break;
ans[h] = ++tot;ans[p] = tot;
p = h + 1;
}
ans[p] = ++tot;ans[ano - 1] = tot;
int siz = f.size();
for(int i = 0 ; i < siz ; i += 4) {
ans[f[i]] = ++tot;ans[f[i + 2]] = tot;
ans[f[i + 1]] = ++tot;ans[f[i + 3]] = tot;
}
f.clear();
for(int i = 1 ; i <= 2 * N ; ++i) if(!ans[i]) f.pb(i);
siz = f.size();
for(int i = 0 ; i < siz ; i += 2) {
ans[f[i]] = ++tot;ans[f[i + 1]] = tot;
}
for(int i = 1 ; i <= 2 * N ; ++i) {out(ans[i]);space;}
enter;
return ;
}
if(cnt % 4 == 2) { for(int i = 1 ; i <= 2 * N ; ++i) {
if(t[i] == 1 && t[i - 1] == 0) f.pb(i);
}
ans[f[0]] = ++tot;ans[f[1]] = tot;
to[f[0]] = f[1] + 1;to[f[1]] = f[0] + 1;
int k = f[1];
while(t[k] == 1) ++k;
ans[k] = ++tot;ans[f[1] - 1] = tot;
to[k] = f[1] - 1;to[f[1] - 1] = k;
} int p = 1;
f.clear();
while(p <= 2 * N) {
vis[p] = 1;
if(t[p] && !ans[p]) f.pb(p);
if(p >= 2 * N) break;
if(to[p] && !vis[to[p]]) p = to[p];
else if(s[p + 1] == '1' && !vis[p + 1]) ++p;
else {
int k = p;
while(k < 2 * N && (s[k + 1] == '0' || vis[k])) ++k;
ans[p] = ++tot;ans[k] = tot;
p = k + 1;
while(p <= 2 * N && vis[p]) ++p;
} }
int siz = f.size();
for(int i = 0 ; i < siz ; i += 4) {
ans[f[i]] = ++tot;ans[f[i + 2]] = tot;
ans[f[i + 1]] = ++tot;ans[f[i + 3]] = tot;
}
f.clear();
for(int i = 1 ; i <= 2 * N ; ++i) {
if(!ans[i]) f.pb(i);
}
siz = f.size();
for(int i = 0 ; i < siz ; i += 2) {
ans[f[i]] = ++tot;ans[f[i + 1]] = tot;
}
for(int i = 1 ; i <= 2 * N ; ++i) {out(ans[i]);space;}
enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

H - Generalized Insertion Sort

为了调这题我特意写了spj,然后发现我数组开小了

简直zz

刷atcoder真是锻炼了我写spj的能力QAQ

我们考虑把所有从叶子开始的一条链挑出来,每次处理它们并删掉,这样只有logn层,因为最多的情况就是一个满二叉树

然后我们如果有一个红点来到根,它所在的底部链有一个红点序列,我们类似插入排序把它插入该到的地方

如果有一个白点,我们把它扔到深度最大的地方,且没有排序过的红点,并标称黑点

但是黑点有可能被顶上去,我们发现黑点被顶上去只可能是放了一个红点,所以复杂度均摊下来就是\(n \log n + n\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define MAXN 4005
#define mo 974711
//#define ivorysi
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 + 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,fa[MAXN],son[MAXN];
vector<int> ne[MAXN];
int a[MAXN],pos[MAXN];
int que[MAXN],tot,pre[MAXN],red,bot[MAXN];
bool vis[MAXN],cov[MAXN],bl[MAXN];
int ans[25005],q;
void drag(int v) {
if(v == 0) return;
ans[++q] = v;
int u = v;
int t = a[u];
while(fa[u] != -1) {
int k = a[fa[u]];
a[fa[u]] = t;
pos[t] = fa[u];
t = k;
u = fa[u];
}
a[v] = t;pos[t] = v;
}
void Process() {
while(red) {
if(vis[a[0]]) {
int u = bot[a[0]];
//while(u != -1 && u == a[u]) {cov[u] = 1;u = fa[u];}
while(1) {
if(!cov[u] || a[u] < a[0]) break;
u = fa[u];
}
drag(u);
while(cov[u]) u = fa[u];
cov[u] = 1;
--red;
}
else {
for(int i = N - 1 ; i >= 0 ; --i) {
if(!cov[i] && !bl[a[i]]) {
bl[a[0]] = 1;
drag(i);break;
}
}
}
}
}
void Solve() {
read(N);
fa[0] = -1;
for(int i = 1 ; i < N ; ++i) {
read(fa[i]);son[fa[i]]++;
ne[fa[i]].pb(i);
}
for(int i = 0 ; i < N ; ++i) {
read(a[i]);
pos[a[i]] = i;
}
while(1) {
tot = 0;
memset(pre,0,sizeof(pre));
memset(bl,0,sizeof(bl));
memset(bot,0,sizeof(bot));
red = 0;
for(int i = N - 1 ; i >= 0 ; --i) {
if(!vis[i]) {
if(!son[i] || (son[i] == 1 && pre[i])) {
que[++tot] = i;
if(fa[i] != -1 && son[fa[i]] == 1) pre[fa[i]] = i;
if(pre[i]) bot[i] = bot[pre[i]];
else bot[i] = i;
vis[i] = 1;
++red;
}
}
}
if(!red) break;
Process();
for(int i = 1 ; i <= tot ; ++i) {
--son[fa[que[i]]];
}
}
out(q);enter;
for(int i = 1 ; i <= q ; ++i) {
out(ans[i]);enter;
}
} int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

I - Simple APSP Problem

一开始想到离散化之后各种分类讨论,瞬间不可写了QAQ

最后就了解了一下简便的写法

就是对于两个相邻的空行,我们把跨过它的贡献统计出来,把它缩成一行,列也一样,这样一个点内之间的路径长度都是0

这样就变成了\(2n * 2n\)的一个矩形,每个矩形里面有一个值代表这个点原来方块的大小

然后对于每个点用BFS跑最短路,两两枚举点对加上即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 1000005
//#define ivorysi
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 + 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 H,W,N;
int x[35],y[35];
int sum[MAXN],a[MAXN],nxtr[MAXN],nxtc[MAXN];
int pos[MAXN],ans;
int g[65][65],r,c,f[65][65];
bool vis[65][65];
int dx[] = {0,-1,0,1},dy[] = {1,0,-1,0}; int mul(int a,int b) {
return 1LL * a * b % MOD;
}
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
void update(int &x,int y) {
x = inc(x,y);
}
queue<pii > Q;
void BFS(int x,int y) {
memset(vis,0,sizeof(vis));
vis[x][y] = 1;f[x][y] = 0;
Q.push(mp(x,y));
while(!Q.empty()) {
pii t = Q.front();Q.pop();
for(int k = 0 ; k < 4 ; ++k) {
int mx = t.fi + dx[k],my = t.se + dy[k];
if(mx >= 1 && mx <= r && my >= 1 && my <= c) {
if(!vis[mx][my] && g[mx][my] != -1) {
f[mx][my] = f[t.fi][t.se] + 1;
Q.push(mp(mx,my));
vis[mx][my] = 1;
}
}
}
}
}
void Solve() {
read(H);read(W);
read(N);
for(int i = 1 ; i <= N ; ++i) {
read(x[i]);read(y[i]);
++x[i];++y[i];
}
for(int i = 1 ; i <= H ; ++i) a[i] = W;
a[H + 1] = 0;
for(int i = 1 ; i <= N ; ++i) --a[x[i]];
for(int i = 1 ; i <= H ; ++i) {
sum[i] = inc(sum[i - 1],a[i]);
}
memset(pos,0,sizeof(pos));
for(int i = 1 ; i <= H ; ++i) pos[i] = i;
for(int i = 1 ; i <= H ; ++i) {
if(a[i] == W && a[i + 1] == W) {
update(ans,mul(sum[i],inc(sum[H],MOD - sum[i])));
pos[i + 1] = pos[i];
nxtr[pos[i]] = i + 2;
}
else nxtr[pos[i]] = i + 1;
}
for(int i = 1 ; i <= W ; ++i) a[i] = H;
a[W + 1] = 0;
for(int i = 1 ; i <= N ; ++i) a[y[i]]--;
for(int i = 1 ; i <= W ; ++i) sum[i] = inc(sum[i - 1],a[i]);
memset(pos,0,sizeof(pos));
for(int i = 1 ; i <= W ; ++i) pos[i] = i;
for(int i = 1 ; i <= W ; ++i) {
if(a[i] == H && a[i + 1] == H) {
update(ans,mul(sum[i],inc(sum[W],MOD - sum[i])));
pos[i + 1] = pos[i];
nxtc[pos[i]] = i + 2;
}
else nxtc[pos[i]] = i + 1;
}
int tmp = 1;
while(tmp != H + 1) {tmp = nxtr[tmp];++r;}
tmp = 1;
while(tmp != W + 1) {tmp = nxtc[tmp];++c;}
int p1 = 1;
for(int i = 1 ; i <= r ; ++i) {
int p2 = 1;
for(int j = 1 ; j <= c ; ++j) {
g[i][j] = mul(nxtr[p1] - p1,nxtc[p2] - p2);
if(nxtr[p1] - p1 == 1 && nxtc[p2] - p2 == 1) {
for(int k = 1 ; k <= N ; ++k) {
if(x[k] == p1 && y[k] == p2) {
g[i][j] = -1;
break;
}
}
}
p2 = nxtc[p2];
}
p1 = nxtr[p1];
}
tmp = 0;
for(int i = 1 ; i <= r ; ++i) {
for(int j = 1 ; j <= c ; ++j) {
if(g[i][j] != -1) {
BFS(i,j);
for(int k = 1 ; k <= r ; ++k) {
for(int h = 1 ; h <= c ; ++h) {
if(g[k][h] != -1) update(tmp,mul(f[k][h],mul(g[i][j],g[k][h])));
}
}
}
}
}
tmp = mul(tmp,(MOD + 1) / 2);
update(ans,tmp);
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

J - Rectangles

神仙数数题呀QAQ

计算出至少有一维是对齐的方案数,可以用容斥

至少一维对齐-至少两维对齐 + 至少三维对齐

然后计算每一维都不对齐的方案数

对于\(p + i,r + j,q + k\)这个点标上\(k\)

那么对于前两维,我对于\(v(x,y,z)\)从下往上一定可以得到一个0,1,2,3,4...c-1,0,1,2,3,4..c - 1的的循环同构串

那么我对于最底层的平面,显然这是一个填满了数的矩形,我们要把它划分成\(a*b\)的矩形,使得每个矩形里数字都一样,问方案数

如果有一行或一列错开了,且这行这列填的数互不相同,那这种情况一定是某一维对齐的情况

所以我们的要填的矩形应该是一个正好被划分成了\(\frac{A*B}{a*b}\)个小矩形

这个时候有一个高度\(h\),它至少占有了一行一列,然后至少在某一层,它移动了某一行,至少在另一层,它动了某一列

且这个高度\(h\)只有一个

我们记占有的行数为\(p\),列数为\(q\),方案数是\((a^q + b^p - 1)^{C / c} - (a^q)^{C / c} - (b^p)^{C / c} + 1\)

然后剩下的要求这种颜色填不成新的行和列,用容斥一下就行,至少零行一样 - 至少一行一样+ 至少两行一样-至少三行一样

列不一一样可以用\(c^{i} - 1\)来限制

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 1000005
//#define ivorysi
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 + 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 A,B,C,a,b,c;
int ans;
int binom[105][105],f[105][105],g[105][105];
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);
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
}
int Calc(int a,int A,int b,int B) {
int res = 0;
update(res,mul(b,fpow(a,B / b)));
update(res,mul(a,fpow(b,A / a)));
update(res,MOD - mul(a,b));
return res;
}
void Trivial() {
update(ans,mul(c,fpow(Calc(a,A,b,B),C / c)));
update(ans,mul(b,fpow(Calc(a,A,c,C),B / b)));
update(ans,mul(a,fpow(Calc(b,B,c,C),A / a)));
update(ans,MOD - mul(mul(b,c),fpow(a,B / b * C / c)));
update(ans,MOD - mul(mul(a,c),fpow(b,A / a * C / c)));
update(ans,MOD - mul(mul(a,b),fpow(c,A / a * B / b)));
update(ans,mul(mul(a,b),c)); }
void Solve() {
Trivial();
binom[0][0] = 1;
for(int i = 1 ; i <= 100 ; ++i) {
binom[i][0] = 1;
for(int j = 1 ; j <= i ; ++j) {
binom[i][j] = inc(binom[i - 1][j - 1],binom[i - 1][j]);
}
}
for(int i = 0 ; i <= A / a ; ++i) {
for(int j = 0 ; j <= B / b ; ++j) {
int t = 1;
for(int k = 0 ; k <= i ; ++k) {
int tmp = inc(fpow(c,i - k),MOD - 1);
tmp = fpow(tmp,j);
update(g[i][j],mul(mul(tmp,binom[i][k]),t));
t = mul(t,MOD - 1);
}
}
}
int all = 0;
for(int i = 1 ; i <= A / a ; ++i) {
for(int j = 1 ; j <= B / b ; ++j) {
if(i == A / a && j == B / b) continue;
int k = fpow(a,j),t = fpow(b,i);
update(f[i][j],fpow(inc(inc(k,t),MOD - 1),C / c));
update(f[i][j],MOD - fpow(k,C / c));
update(f[i][j],MOD - fpow(t,C / c));
update(f[i][j],1);
int tmp = mul(f[i][j],mul(binom[A / a][i],binom[B / b][j]));
tmp = mul(tmp,c);
tmp = mul(tmp,g[A / a - i][B / b - j]);
update(all,tmp);
}
}
all = mul(all,mul(a,b));
update(ans,all);
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
read(a);read(b);read(c);read(A);read(B);read(C);
if(A % a == 0 && B % b == 0 && C % c == 0) Solve();
else puts("0");
return 0;
}

【AtCoder】AtCoder Petrozavodsk Contest 001的更多相关文章

  1. 【HDU5187】zhx's contest

    [问题描述] 作为史上最强的刷子之一,zhx的老师让他给学弟(mei)们出n道题.zhx认为第i道题的难度就是i.他想要让这些题目排列起来很漂亮. zhx认为一个漂亮的序列{ai}下列两个条件均需满足 ...

  2. 【AtCoder】AtCoder Grand Contest 035 解题报告

    点此进入比赛 \(A\):XOR Circle(点此看题面) 大致题意: 给你\(n\)个数,问是否能将它们摆成一个环,使得环上每个位置都是其相邻两个位置上值的异或值. 先不考虑\(0\),我们假设环 ...

  3. 【AtCoder】AISing Programming Contest 2019

    本来以为是1199rated的..仔细一看发现是1999,所以就做了一下 这场涨分很轻松啊...为啥又没打 等pkuwc考完我一定打一场atcoder(咕咕咕,咕咕咕,咕咕咕咕咕咕咕~) 但是其实我思 ...

  4. 【AtCoder】Tenka1 Programmer Contest 2019

    Tenka1 Programmer Contest 2019 C - Stones 题面大意:有一个01序列,改变一个位置上的值花费1,问变成没有0在1右边的序列花费最少多少 直接枚举前i个都变成0即 ...

  5. 【AtCoder】M-SOLUTIONS Programming Contest

    M-SOLUTIONS Programming Contest A - Sum of Interior Angles #include <bits/stdc++.h> #define fi ...

  6. 【AtCoder】Yahoo Programming Contest 2019

    A - Anti-Adjacency K <= (N + 1) / 2 #include <bits/stdc++.h> #define fi first #define se se ...

  7. 【AtCoder】Tenka1 Programmer Contest

    C - 4/N 列出个方程枚举解一下 #include <bits/stdc++.h> #define fi first #define se second #define pii pai ...

  8. 【AtCoder】KEYENCE Programming Contest 2019

    A - Beginning 这个年份恐怕需要+2 #include <bits/stdc++.h> #define fi first #define se second #define p ...

  9. 【AtCoder】Dwango Programming Contest V题解

    A - Thumbnail 题意简述:给出N个数,找出N个数中和这N个数平均值绝对值最小的数 根据题意写代码即可= = #include <bits/stdc++.h> #define f ...

随机推荐

  1. 【BZOJ1432】[ZJOI2009]Function(找规律)

    [BZOJ1432][ZJOI2009]Function(找规律) 题面 BZOJ 洛谷 题解 这...找找规律吧. #include<iostream> using namespace ...

  2. 【COGS1752】 BOI2007—摩基亚Mokia

    http://cogs.pro/cogs/problem/problem.php?pid=1752 (题目链接) 题意 给出$n*n$的棋盘,单点修改,矩阵查询. Solution 离线以后CDQ分治 ...

  3. 面试题:get和post的本质区别

    前言:相信小伙伴们面试时候一定都遇到过这个问题,即使没有遇到过,至少也听说过,网上资料一大片,大概每个人都能说出来一些.但是总感觉面试装逼不成功,所以就翻阅了部分资料,进一步整理了下. 一般当我们提到 ...

  4. 使用alien命令让deb包和rpm包互相转换

    OS version: CentOS7 / Debian9 发现alien这个命令时很惊喜,之前在debian上安装etcd找不到安装包感觉很不科学,有了alien命令事情一下就变简单了. 这里以et ...

  5. SpringBoot整合Mybatis之xml

    SpringBoot整合Mybatis mybatis ORM框架.几个重要的概念: Mapper配置 : 可以使用基于XML的Mapper配置文件来实现,也可以使用基于Java注解的Mybatis注 ...

  6. RBAC: 基于角色的访问控制(Role-Based Access Control)

    本文只讨论两种基于角色的访问控制的不同点,不涉及权限设计的数据库设计. 基于角色的访问控制(Role-Based Access Control)可分为隐式角色访问控制和显式角色访问控制. 隐式角色访问 ...

  7. HDU 4280 ISAP+BFS 最大流 模板

    Island Transport Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  8. bzoj千题计划198:bzoj1084: [SCOI2005]最大子矩阵

    http://www.lydsy.com/JudgeOnline/problem.php?id=1084 m=1: dp[i][j] 前i个数,选了j个矩阵的最大和 第i个不选:由dp[i-1][j] ...

  9. 并查集:POJ 1182 食物链 复习

    #include <iostream> #include <algorithm> #include <cstring> #include <cstdlib&g ...

  10. 关于如何在Python中使用静态、类或抽象方法的权威指南

    Python中方法的工作方式 方法是存储在类属性中的函数,你可以用下面这种方式声明和访问一个函数 >>> class Pizza(object): ... def __init__( ...