若是\(X\)是\(Y\)的倍数的话不存在
能够输出\(X \cdot (\frac{Y}{gcd(X,Y)} - 1)\)node
#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; }
a<b的话,这个位置必定会合法,若是a > b的话不可能再小于b了,因此咱们看看在用全部位置的a增长不超过b的位置的状况下,能一共给b增长多少,若是这个增长数大于全部a > b的a和b差值的和就合法c++
#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"); }
二分
我知道了最左和最右两边的后,若是这个位置和两边都是奇数区间的话
例如
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; }
把每一个点排序,若是加进来的点所在的联通块没有点,那么把这个点放进队列里,若是还有别的联通块里的点,就把这个点和别的联通块连一条边,而后删掉这个点,把这两个联通块用并查集连在一块儿spa
若是没有别的联通块里的点,那么就把这个点扔进队列,把队列打上标记,若是以后还有别的联通块的点来,而后取出队列里这个联通块中的点和新加的点连一条边
直到队列里只有一个点就把标记删除rest
若是只有两个联通块,队列没有标记,且有多于两个点,这两个点之间连一条边退出就行了code
保证每次都是取了最小的两个点连边(第一种操做也是保证取了最小的由于我保证了在队列里同联通块的点必定会被用,因此这个点也可用)排序
#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; }
简单的树dp队列
设\(dp[v]\)为以0为根时\(v\)点子树里最少须要选择的点get
\(dp[u] = \sum_{v\in son(u)} dp[v]\)
计算一个\(cnt\)为\(v\)中\(dp[v]\)不为0的个数
$dp[u] += max(0,son - 1 - cnt) $it
而后就是换根了,不难换具体看代码吧
#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(); }
若是你很熟练,你能够想到给一条路径加异或就至关于给两个端点到根加异或
咱们从底到根算出每一个点都须要加多少异或,而后给相同的异或值两两配对,这个时候会有单出来的
例如
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; }
在好久之前的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(); }
为了调这题我特地写了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(); }
一开始想到离散化以后各类分类讨论,瞬间不可写了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(); }
神仙数数题呀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; }