fjnu09暑期训练赛题解
题目地址密码:000111
Read more…
比赛地址
题目不分难易,即使题目很简单,不同的人也会有不同的做法,多看别人的程序,可以拓宽自己的思路
Read more…
简单深搜,注意如何判断两个方块是否相通
#include <iostream> using namespace std; #define TOLEFT(T) ((T) == 'A' || (T) == 'C' || (T) == 'F' || (T) == 'G' || (T) == 'H' || (T) == 'I' || (T) == 'K') #define TORIGHT(T) ((T) == 'B' || (T) == 'D' || (T) == 'F' || (T) == 'G' || (T) == 'I' || (T) == 'J' || (T) == 'K') #define TOUP(T) ((T) == 'A' || (T) == 'B' || (T) == 'E' || (T) == 'G' || (T) == 'H' || (T) == 'J' || (T) == 'K') #define TODOWN(T) ((T) == 'C' || (T) == 'D' || (T) == 'E' || (T) == 'H' || (T) == 'I' || (T) == 'J' || (T) == 'K') int h, w; char mp[60][60]; int v[60][60]; const int dh[] = {-1, 0, 1, 0}; const int dw[] = {0, 1, 0, -1}; const int ZONG = 0; const int HENG = 1; bool isConnect(int h1, int w1, int h2, int w2, int dir) { if(dir == HENG) { if(w1 > w2) { swap(h1, h2); swap(w1, w2); } return TORIGHT(mp[h1][w1]) && TOLEFT(mp[h2][w2]); } else { if(h1 > h2) { swap(h1, h2); swap(w1, w2); } return TODOWN(mp[h1][w1]) && TOUP(mp[h2][w2]); } } void dfs(int i, int j) { v[i][j] = 1; int th, tw; for(int k = 0; k < 4; ++k) { th = i + dh[k]; tw = j + dw[k]; if(th < 0 || th >= h || tw < 0 || tw >= w || v[th][tw] == 1 || !isConnect(i, j, th, tw, ((k&1)?HENG:ZONG))) continue; dfs(th, tw); } } int main() { int ans; while(scanf("%d%d", &h, &w)) { if(h < 0 || w < 0) break; ans = 0; for(int i = 0; i < h; ++i) scanf("%s", mp[i]); memset(v, 0, sizeof(v)); for(int i = 0; i < h; ++i) for(int j = 0; j < w; ++j) if(v[i][j] == 0) { ++ans; dfs(i, j); } printf("%d\n", ans); } }
题目地址
注意该题不能从外面绕
判断两点是否可以消去
消去可能是可以直接一条横线连,也可能是一个折的线或者是二个折的线
我用的方法,可以同时全部考虑进去
假设A,B是两个要判断是否消去的点,如果两点数字不同,或者都为0,当然不能消去
否则计算出A,B两点向四个方向能延伸到多远
以
1 2 3 4
0 0 0 0
4 3 2 1
为例
如果A=(1,1),B=(3,4)(坐标从1开始)
那么A按上右下左的顺序能延伸的范围是1, 1, 2, 1
B按上右下左的顺序能延伸的范围是2, 4, 3, 4
即向上下的话,是记录其纵坐标的范围,左右的话是记录横坐标的范围
现在先来判断上下是否连接,
那么先得出A,B两者左右延伸的公共范围,易知A左右延伸为(1,1),B为(4,4)故其没有公共范围
再来判断左右是否连接
那么先得出A,B两者上下延伸的公共范围,易知A上下延伸为(1,2),B为(2,3)故其公共范围为(2,2)
遍历纵坐标为(2,2)中的所有数且横坐标为A的横坐标的点,看每个点左右延伸范围是否有包括B点,如果有则可以消去
注意到两点刚好邻接的情况,应该将延伸范围左右扩大1
例如
1 1
这个明显可以消去,但如果按延伸范围是否包括的话,则为不能消去,所以必须加1,注意到代码注释的地方
#include <iostream> using namespace std; int a[1001][1001], h, w; const int dh[] = {-1, 0, 1, 0}; const int dw[] = {0, 1, 0, -1}; struct Point { int h, w; int dir[4]; } st, en; void cal(Point v, int *p) { Point tmp; for(int i = 0; i < 4; ++i) { tmp = v; do { tmp.h += dh[i]; tmp.w += dw[i]; } while(tmp.h >= 0 && tmp.h < h && tmp.w >= 0 && tmp.w < w && a[tmp.h][tmp.w] == 0); tmp.h -= dh[i]; tmp.w -= dw[i]; p[i] = ((i&1) ? tmp.w : tmp.h); } } void cal1(Point v, int *p, int i) { Point tmp; tmp = v; do { tmp.h += dh[i]; tmp.w += dw[i]; } while(tmp.h >= 0 && tmp.h < h && tmp.w >= 0 && tmp.w < w && a[tmp.h][tmp.w] == 0); tmp.h -= dh[i]; tmp.w -= dw[i]; p[i] = ((i&1) ? tmp.w : tmp.h); } bool solve() { if(a[st.h][st.w] == 0 || a[st.h][st.w] != a[en.h][en.w]) return false; int mmin, mmax; cal(st, st.dir); cal(en, en.dir); Point a1 = st, a2 = en; if(a1.w > a2.w) swap(a1, a2); mmin = max(a1.dir[0], a2.dir[0]); mmax = min(a1.dir[2], a2.dir[2]); Point tmp; tmp.w = a1.w; for(int i = mmin; i <= mmax; ++i) { tmp.h = i; cal1(tmp, tmp.dir, 1); //这里必须加1,理由看开头注释 if(tmp.dir[1] + 1 >= a2.w) return true; } if(a1.h > a2.h) swap(a1, a2); mmin = max(a1.dir[3], a2.dir[3]); mmax = min(a1.dir[1], a2.dir[1]); tmp.h = a1.h; for(int i = mmin; i <= mmax; ++i) { tmp.w = i; cal1(tmp, tmp.dir, 2); //这里必须加1,理由看开头注释 if(tmp.dir[2] + 1 >= a2.h) return true; } return false; } int main() { int p; while(scanf("%d%d", &h, &w)) { if(h == 0 && w == 0) break; for(int i = 0; i < h; ++i) for(int j = 0; j < w; ++j) scanf("%d", &a[i][j]); scanf("%d", &p); while(p--) { scanf("%d%d%d%d", &st.h, &st.w, &en.h, &en.w); st.h -= 1, st.w -= 1, en.h -= 1, en.w -= 1; solve() ? puts("YES") : puts("NO"); } } return 0; }
1062* 昂贵的聘礼 枚举等级限制+dijkstra
1087* A Plug for UNIX 2分匹配
1094 Sorting It All Out floyd 或 拓扑
1112* Team Them Up! 2分图染色+DP
1135 Domino Effect 最短路
1149* PIGS 网络流
1161* Walls floyd
1201 Intervals 差分约束
1236* Network of Schools 强联通
1251 Jungle Roads MST
1273 Drainage Ditches 最大流
1275* Cashier Employment 差分约束
1364 King 差分约束
1459 Power Network 网络流
1502 MPI Maelstrom floyd
1511* Invitation Cards 最短路
1637* Sightseeing tour 混合图欧拉回路-网络流
1716 Integer Intervals 差分约束
1724* ROADS 最短路-拆点
1780* Code 欧拉回路
1789 Truck History 最小生成树
1797 Heavy Transportation 最小生成树
1847 Tram 最短路
1904* King’s Quest 强联通
1949 Chores 最短路
2060 Taxi Cab Scheme 2分匹配
2075 Tangled in Cables 最小生成树
2112 Optimal Milking 网络流
2125 Destroying The Graph 最小割
2135 Farm Tour 费用流
2139 Six Degrees of Cowvin Bacon floyd
2230 Watchcow 欧拉回路
2267* From Dusk till Dawn or: Vladimir the Vampire 最短路
2289 Jamie’s Contact Groups 网络流
2337 Catenyms 欧拉通路
2349 Arctic Network 最小生成树
2369 Genealogical tree 拓扑序
2387 Til the Cows Come Home 最短路
2391* Ombrophobic Bovines 最大流
2394 Checking an Alibi 最短路
2396* Budget 网络流
2421* Constructing Roads 最小生成树
2455 Secret Milking Machine 网络流
2457 Part Acquisition 最短路
2516 Minimum Cost 费用流
2553* The Bottom of a Graph 强联通
2570 Fiber Network floyd
2584 T-Shirt Gumbo 网络流
2723 Get Luffy Out 2-sat
2724 Purifying Machine 2分匹配
2728 Desert King 最优比例生成树
2749* Building roads 2-sat
2762 Going from u to v or from v to u? 强联通
2949* Word Rings 差分约束
2983 Is the Information Reliable? 差分约束
2987 Firing 最小割(求解正确性??)
3020 Antenna Placement 2分匹配
3041 Asteroids 2分匹配
3072* Robot 最短路
3160 Father Christmas flymouse 强联通
3164 Command Network 最小树形图
3169 Layout 差分约束
3177 Redundant Paths 双联通分量
3189 Steady Cow Assignment 网络流
3204 Ikki’s Story I – Road Reconstruction 最大流
3207 Ikki’s Story IV – Panda’s Trick 2分图
3216 Repairing Company 2分匹配
3228 Gold Transportation 网络流
3255 Roadblocks 最短路
3259 Wormholes 最短路
3268 Silver Cow Party 最短路
3275 Ranking the Cows floyd
3281 Dining 最大流
3308 Paratroopers 最小割
3310 Caterpillar
3311 Hie with the Pie floyd
3328 Cliff Climbing 最短路
3343 Against Mammoths 2分匹配
3352 Road Construction 桥
3439 Server Relocation 最短路
3463 Sightseeing 最短路
3469 Dual Core CPU 最小割
3487 The Stable Marriage Problem 稳定婚姻
3522 Slim Span 最小生成树
3594 Escort of Dr. Who How 最短路
3623 Wedding 2-sat
3653 Here We Go(relians) Again 最短路
3659* Cell Phone Network 最小支配集
3660 Cow Contest 拓扑
3662* Telephone Lines 最短路
3678 Katu Puzzle 2-sat
3683* Priest John’s Busiest Day 2-sat求解
3687 Labeling Balls 差分约束 或 拓扑
3692 Kindergarten 2分匹配
3694 Network 无向图缩点
题目地址
给定一个不大于10^100的数K和一个不大于10^6的数L,求是否存在K的最小素因子,且该因子小于L
暴力即可,为了方便,使用JAVA
Memory: 9516K
Time: 1485MS
import java.io.*; import java.util.*; import java.math.*; public class Main { private int[] a; private int top; private void init() { a = new int[1000001]; a[0] = 2; top = 1; for (int i = 3; i <= 1000000; i += 2) { if (a[i] == 0) { a[top++] = i; for (int j = i + i; j <= 1000000; j += i) { a[j] = 1; } } } } private void creat() { init(); Scanner cin = new Scanner(new BufferedInputStream(System.in)); next: while (true) { String b1 = cin.next(); int b2 = cin.nextInt(); if (b1.compareTo("0") == 0 && b2 == 0) { break; } BigInteger a1 = new BigInteger(b1); BigInteger a2 = new BigInteger("0"); for (int i = 0; i < top && a[i] < b2; i++) { if (a1.mod(a2.valueOf(a[i])).compareTo(BigInteger.ZERO) == 0) { System.out.println("BAD " + new Integer(a[i]).toString()); continue next; } } System.out.println("GOOD"); } } public static void main(String[] args) { Main e = new Main(); e.creat(); } }
题目地址
给定一个仅由小写字母组成的序列,按一定的规则排列,输出给定序列在排在所有序列中的哪里
规则是,长度短的排在前面,长度相同的,按字典序排序,而且序列是合法的当且仅当从左算起第i位的字母必须严格小于第i位后面的所有字母,即vwxyz是合法的,vwyxz是不合法的.
一个大致序列如下:
a -> 1
b -> 2
.
.
z -> 26
ab -> 27
ac -> 28
.
.
az -> 51
bc -> 52
.
.
vwxyz -> 83681
对于不合法序列,输出0
首先,我们先不考虑序列不合法的情况,那么对于一个n位的序列,其位置可能达到s=C(26,1)+C(26,2)+…+C(26,n),我们算出s的值,然后再减掉不合法的序列以及大于给定序列的其他序列的情况.假设给定序列是abcd,n=4,那么我们减掉所有以a以后字母开头的序列个数,即C(25,4),现在我们剩下的就是以a开头的不合法序列和大于abcd但小于axyz的合法序列,对于第二位,我们减掉以b以后字母为第二位的序列,即C(24,3),现在剩下的是以ab开头的不合法序列和大于abcd但小于abyz的合法序列,以此类推即可.
Memory: 132K
Time: 0MS
#include <iostream> using namespace std; int C(int n, int r) { int i, j, s = 1; if(n - r > r) r = n - r; for(i = 0, j = 1; i < r; i++) for(s *= n - i; j <= r && !(s % j); j++) s /= j; return s; } int main() { char s[6]; int l, i, j, res; while(scanf("%s", s) != EOF) { l = strlen(s); res = 0; for(i = 0; i < l - 1; i++) for(j = i + 1; j < l; j++) if(s[i] >= s[j]) { puts("0"); goto next; } for(i = 1; i <= l; i++) res += C(26, i); for(i = 0; i < l; i++) res -= C(122-s[i], l-i); printf("%d\n", res); next:; } return 0; }
题目地址
这题着实写了大半个下午..
题目大意是求A^B中,所有因数的和模9901的值.
稍微推下公式易知,对于一个数A,若A=p1^n1 * p2^n2 * P3^n3….,其中p1,p2,p3..都是A的质因数,则其所有因数和应该为(p1^0 + p1^1 + p1^2+…+p1^n1) * (p2^0 + p2^1+…+p2^n2) * …所以A^B的所有因子和为(p1^0 + p1^1 + p1^2+…+p1^(n1*B)) * (p2^0 + p2^1+…+p2^(n2*B)) * …,根据几何级数的求和公式有,sum = (p1^(n1*B+1) – 1) / (p1-1) * (p2^(n2*B+1) – 1) / (p2 – 2) *…
题目即求sum % 9901的值.
而对于该式,我们只需用对分子的积求模,然后乘以分母对9901的逆元即可,求逆元用扩展欧几里德.
这里有一个恶心的地方,对于某个数p1,如果p1%9901的值等于1,那么套用上述公式是不正确的,因为此时相当于几何级数中的倍数为1,那样是不能套用公式的,正确的和应该为n1*B+1.
Memory: 144K
Time: 0MS
#include <iostream> using namespace std; const int M = 9901; const int N = 7073; typedef long long ll; int p[908] = {2}, l = 1, fac[35][2], top, ans; bool prime[N+1] = {1, 1}; void init() { int i, j; for(i = 3; i <= N; i += 2) { if(!prime[i]) p[l++] = i; for(j = 1; j <= l && i * p[j] <= N; j++) { prime[i*p[j]] = 1 ; if(!(i%p[j])) break; } } } void split(int n) { int i; top = 0; for(i = 0; i < l; i++) if(!(n%p[i])) { fac[top][0] = 0, fac[top][1] = p[i]; while(!(n%p[i])) fac[top][0]++, n /= p[i]; top++; if(n == 1 || n < N && !prime[n]) break; } if(n != 1) fac[top][0] = 1, fac[top++][1] = n; } int Pow(int a, ll b) { int t = 1; while(b) { if(b & 1) t = t * a % M; a = a * a % M; b >>= 1; } return t; } int ex_gcd(int a, int b, int &x, int &y) { if(!b) {x = 1; y = 0; return a;} int ans = ex_gcd(b, a%b, x, y), t = x; x = y; y = t - (a / b) * y; return ans; } int main() { int a, b, res, i, res1, x, y, tmp; init(); while(~scanf("%d%d", &a, &b)) { split(a); res = res1 = 1; for(i = 0; i < top; i++) { tmp = Pow(fac[i][1] % M, (ll)fac[i][0] * b + 1); if(tmp == 1) res = (res * ((ll)fac[i][0] * b + 1)) % M; else { res *= (tmp - 1 + M) % M; if(res >= M) res %= M; res1 = res1 * (fac[i][1] - 1); if(res1 >= M) res1 %= M; } } ex_gcd(res1, M, x, y); printf("%d\n", (res * ((x + M) % M)) % M); } return 0; }
题目地址
for (variable = A; variable != B; variable += C)
statement;
题目给定A,B,C,问这个循环执行多少次会停止或者永远不停止.题目还给定一个k,代表当数值达到2^k时,会自动重新从0开始.
很明显,就是要我们求(A + C * x) % 2^k = B中,x的值即C*x % 2^k = B – A,即一个赤裸裸的扩展欧几里德
Memory: 132K
Time: 0MS
#include <iostream> using namespace std; typedef long long ll; ll ex_gcd(ll a, ll b, ll &x, ll &y) { if(!b) {x = 1; y = 0; return a;} ll ans = ex_gcd(b, a%b, x, y), t = x; x = y; y = t - (a / b) * y; return ans; } int main() { ll a, b, c, x, y, t, s; int k, i; while(scanf("%lld%lld%lld%d", &a, &b, &c, &k), a || b || c || k) { s = (ll)1 << k; t = ex_gcd(c, s, x, y); b -= a; if(b % t) { puts("FOREVER"); continue; } printf("%lld\n", (x * b / t % (s/t) + (s / t)) % (s / t)); } return 0; }
题目地址
题目大意是,给定一个小于50W位的数N,正常情况下,该数应该等于n^n,如果能找到一个n,使得n^n=N,则输出N,否则有可能是该数N中其中唯一的一位发生了错误(N的长度不变),则应该输出-1
容易知道如果N的长度为1,则只有N==1或N==4才有解。
对于其他情况,首先我们知道n^n的位数应该等于w=log10(n^n)+1=nlog10(n)+1,由于数N最多为50W位,故容易得出n最大为100000,那么我们可以先二分找出n的值,然后判断n^n与N是否相等,如果相等则输出n,否则输出-1,那么如何判断相等呢
假设N原来的值为a,变化后的值为b,因为最多只可能改变一位,我们假设a+k*10^(n-1)=b,即a的第n位多了k,这里我们只假设k为正的情况,为负的同理,那么有0<=k<=9,且第n位加了k后不产生进位。我们即要判断a跟a+k*10^(n-1)是否相等,为了避免直接计算a的值,我们想到了应该对两边进行取模运算,那么应该对什么数求模,则如果发生改变,那么余数绝对不相等呢,这里我们取该数为99,那么对于n>=3有
(a+k*10^(n-1))%99 = a%99 + k * 10^(n-1)%99,因为10^(n-1)%99=1(n>=3)
所以(a+k*10^(n-1))%99 = a%99 + k %99
如果看出当k!=0时,a%99+k%99的值绝对不等于a%99的值,所以要判断n^n与N是否相等,只需判断n^n%99与N%99是否相等即可。
Memory: 808K
Time: 0.06S
#include <iostream> #include <algorithm> #include <vector> #include <queue> #include <cmath> using namespace std; const int M = 99; char a[500002]; int Pow(int a, int b, int c) { int t = 1; while(b) { if(b & 1) t = t * a % c; a = a * a % c; b >>= 1; } return t; } int main() { int t, i, l, r, m, len, res, len1; scanf("%d", &t); while(t--) { scanf("%s", a); for(i = len = res = 0; a[i]; i++, len++) res = (res * 10 + a[i] - '0') % M; if(len == 1) { printf("%d\n", res == 1 ? 1 : (res == 4 ? 2 : -1)); continue; } l = 3, r = 100000; while(l <= r) { m = (l + r) >> 1; len1 = (int)(m * log10((double)m)) + 1; if(len1 == len) break; if(len1 < len) l = m + 1; else r = m - 1; } if(Pow(m%M, m, M) == res) printf("%d\n", m); else puts("-1"); } return 0; }
Recent Comments