Andrew Stankevich Contest #1 (ASC #1) 练习赛
2015-04-10 12:57:22
总结:定期的 asc 训练赛...
第一场打得不是很认真... 中间走神了,以后尽量选在整块的时间来打 asc 。
5h 过了 4题,5h1min过了第 5题,赛后补齐了剩下的3题... 说实话补最后一题(耗时2days)都差点放弃了。。
※本场的一些收获:
(1)完善了高精度模板。
(2)学习了dinic当前弧优化。
(3)学习了上下界流的第二种建图方式。
(4)收获了高斯消元另一个模型。
(5)学习了如何判断点在多边形内。
(6)学习了如何利用dfs树找简单环。
A题:
可以把题目转化为:给出N,找到一个K与N互质且K<=N/2。
试了一些数据发现规律:如果N为奇数,那么答案为(N-1)/2;
如果N为偶数,那么判断N/2的奇偶性,若N/2为偶则答案为N/2-1,若N/2为奇数则答案为N/2-2。
由于题目的数据范围很大... 需要上高精度。
1 #include <cstdio> 2 #include <string> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 const int maxn = 3000; 7 8 struct bign{ 9 int len,s[maxn + 5]; 10 11 //初始化与赋值 12 bign(){ 13 memset(s,0,sizeof(s)); 14 len = 1;//因为0的存在 15 } 16 17 bign operator = (const char *num){ 18 len = strlen(num); 19 for(int i = 0; i < len; ++i) 20 s[i] = num[len - i - 1] - '0';//倒序转化成数字 21 return *this; 22 } 23 24 bign operator = (int num){ 25 char ts[maxn + 5]; 26 sprintf(ts,"%d",num); 27 *this = ts; 28 return *this; 29 } 30 31 bign(int num){ 32 *this = num; 33 } 34 35 bign(const char *num){ 36 *this = num; 37 } 38 //bign的str型转化 39 string str() const{ 40 string res = ""; 41 for(int i = len - 1; i >= 0; --i) 42 res += (char)(s[i] + '0'); 43 if(res == "") 44 res = "0"; 45 return res; 46 } 47 //运算符重载 48 //高精度加 49 bign operator + (const bign & b) const{ 50 bign sum; 51 sum.len = 0; 52 for(int i = 0, g = 0; g || i < max(len,b.len); ++i){ 53 int x = g;//x:暂存和,g:进位 54 if(i < len) x += s[i]; 55 if(i < b.len) x += b.s[i]; 56 sum.s[sum.len++] = x % 10; 57 g = x / 10; 58 } 59 return sum; 60 } 61 62 //高精度减 63 bign operator - (const bign & b) const{ 64 bign dif; 65 int maxlen = (len > b.len) ? len : b.len; 66 for(int i = 0; i < maxlen; ++i){ 67 dif.s[i] += s[i] - b.s[i]; 68 if(dif.s[i] < 0){ 69 dif.s[i] += 10; 70 --dif.s[i + 1]; 71 } 72 } 73 dif.len = maxlen; 74 while(dif.s[dif.len - 1] == 0 && dif.len > 1) 75 --dif.len; 76 return dif; 77 } 78 79 //高精度乘,实际上加和乘对进位的处理有所不同 80 bign operator * (const bign &b) const{ 81 bign pro; 82 pro.len = 0; 83 for(int i = 0; i < len; ++i){ 84 for(int j = 0; j < b.len; ++j){ 85 pro.s[i + j] += (s[i] * b.s[j]); 86 pro.s[i + j + 1] += pro.s[i + j] / 10; 87 pro.s[i + j] %= 10; 88 } 89 } 90 pro.len = len + b.len + 1;//这里注意pro.len初始值可能是题目数字范围两倍 91 while(pro.s[pro.len - 1] == 0 && pro.len > 1) 92 --pro.len;//最后一位不管是不是0都不能让len - 1 93 if(pro.s[pro.len]) 94 ++pro.len;//这句有待商讨 95 return pro; 96 } 97 98 //高精度乘以低精度 99 bign operator * (const int num) const{ 100 int c = 0,t; 101 bign pro; 102 for(int i = 0; i < len; ++i){ 103 t = s[i] * num + c; 104 pro.s[i] = t % 10; 105 c = t / 10; 106 } 107 pro.len = len; 108 while(c != 0){ 109 pro.s[pro.len++] = c % 10; 110 c /= 10; 111 } 112 return pro; 113 } 114 115 //高精度除,模拟连减 116 bign operator / (const bign & b) const{ 117 bign quo,f; 118 for(int i = len - 1; i >= 0; --i){ 119 f = f * 10; 120 f.s[0] = s[i]; 121 while(f >= b){ 122 f = f - b; 123 ++quo.s[i]; 124 } 125 } 126 quo.len = len; 127 while(quo.s[quo.len - 1] == 0 && quo.len > 1) 128 --quo.len; 129 return quo; 130 } 131 132 //比较运算符 133 bool operator < (const bign & b) const{ 134 if(len != b.len) return len < b.len; 135 for(int i = len - 1; i >= 0; --i)//从高位开始比较 136 if(s[i] != b.s[i]) 137 return s[i] < b.s[i]; 138 //如果 本身 == b 139 return false; 140 } 141 142 bool operator > (const bign &b) const{ 143 return b < *this;//代表 本身 > b 144 } 145 146 bool operator <= (const bign &b) const{ 147 return !(b < *this);//带表 !(本身 > b) 148 } 149 150 bool operator >= (const bign &b) const{ 151 return !(*this < b); 152 } 153 154 bool operator != (const bign &b) const{ 155 return *this < b || b < *this; 156 } 157 158 bool operator == (const bign &b) const{ 159 return !(*this < b) && !(b < *this); 160 } 161 162 friend istream & operator >> (istream & in,bign & x); 163 friend ostream & operator << (ostream & out,const bign & x); 164 }; 165 166 istream & operator >> (istream & in,bign & x){ 167 string ts; 168 in >> ts; 169 x = ts.c_str(); 170 return in; 171 } 172 173 ostream & operator << (ostream & out,const bign & x){ 174 out << x.str(); 175 return out; 176 } 177 int main(){ 178 freopen("china.in","r",stdin); 179 freopen("china.out","w",stdout); 180 bign N; 181 bign one = 1,two = 2; 182 cin >> N; 183 bign hf = N / 2; 184 int suf = N.s[0]; 185 if(suf & 1){ 186 cout << hf << endl; 187 } 188 else{ 189 if(hf.s[0] & 1) cout << hf - two << endl; 190 else cout << hf - one << endl; 191 } 192 return 0; 193 }
B题:
这题比赛时没看,是一道上下界最大流。推荐博客。
所以用经典的处理方法,首先建立超级源点S和超级汇点E,一条 u->v 的边,下界为L[i],上界为C[i]。
则:建边 S->v,流量为L[i],建边 u->E,流量为L[i],再建边 u->v,流量为C[i]-L[i] 。
跑一遍最大流之后判断总流量是否为 Sigma(L[i]),若是则YES,再根据每条边的剩余流量和上界C[i]计算出流量并输出。
否则就是NO。
注意:这题若用 dinic 必须加上当前弧优化!
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int MAXN = 410; 25 const int MAXM = 410 * 210; 26 27 int N,M,st,ed; 28 int first[MAXN],now[MAXN],ecnt; 29 int lev[MAXN]; 30 31 struct edge{ 32 int v,next,c,top; 33 }e[MAXM * 3]; 34 35 void Init(){ 36 MEM(first,-1); 37 ecnt = 0; 38 } 39 40 void Add_edge(int u,int v,int c,int d){ 41 e[ecnt].next = first[u]; 42 e[ecnt].v = v; 43 e[ecnt].c = c; 44 e[ecnt].top = d; 45 first[u] = ecnt++; 46 47 e[ecnt].next = first[v]; 48 e[ecnt].v = u; 49 e[ecnt].c = 0; 50 e[ecnt].top = d; 51 first[v] = ecnt++; 52 } 53 54 bool Bfs(){ 55 queue<int> Q; 56 while(!Q.empty()) Q.pop(); 57 MEM(lev,-1); 58 lev[st] = 0; 59 Q.push(st); 60 while(!Q.empty()){ 61 int cur = Q.front(); Q.pop(); 62 for(int i = first[cur]; ~i; i = e[i].next){ 63 int v = e[i].v; 64 if(e[i].c > 0 && lev[v] < 0){ 65 lev[v] = lev[cur] + 1; 66 Q.push(v); 67 } 68 } 69 } 70 return lev[ed] != -1; 71 } 72 73 int Dfs(int p,int minf){ 74 if(p == ed || minf == 0) return minf; 75 for(int & i = now[p]; ~i; i = e[i].next){ 76 int v = e[i].v; 77 if(lev[v] == lev[p] + 1 && e[i].c > 0){ 78 int d = Dfs(v,min(e[i].c,minf)); 79 if(d > 0){ 80 e[i].c -= d; 81 e[i ^ 1].c += d; 82 return d; 83 } 84 } 85 } 86 return 0; 87 } 88 89 int Dinic(){ 90 int max_flow = 0,pl; 91 while(Bfs()){ 92 memcpy(now,first,sizeof(first)); 93 while((pl = Dfs(st,INF)) > 0) 94 max_flow += pl; 95 } 96 return max_flow; 97 } 98 99 int main(){ 100 freopen("cooling.in","r",stdin); 101 freopen("cooling.out","w",stdout); 102 int a,b,c,d; 103 scanf("%d%d",&N,&M); 104 Init(); 105 st = 0; 106 ed = N + 1; 107 int sum = 0; 108 REP(i,M){ 109 scanf("%d%d%d%d",&a,&b,&c,&d); 110 sum += c; 111 Add_edge(a,b,d - c,d); 112 Add_edge(st,b,c,d); 113 Add_edge(a,ed,c,d); 114 } 115 int max_flow = Dinic(); 116 if(max_flow == sum){ 117 printf("YES\n"); 118 for(int i = 0,cnt = 1; cnt <= M; cnt++,i += 6) 119 printf("%d\n",e[i].top - e[i].c); 120 } 121 else printf("NO\n"); 122 return 0; 123 }
C题:
题意相当之费解...
小翻译下:就是给出一颗代表上下级关系的树,每个节点的状态有3种:(1)让下级拿奖金。(2)接受上级让自己拿奖金的许可。(3)什么都不做。
限制:一个节点不能同时进行(1)和(2),一个上司只能让一个下级拿奖金。
其实就是个染色问题,发现贪心地从最后一个节点(叶子)开始尽量染色即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int MAXN = 500010; 25 26 int N; 27 int fa[MAXN]; 28 int given[MAXN]; 29 vector<int> ans; 30 vector<int> g[MAXN]; 31 queue<int> Q; 32 33 int main(){ 34 freopen("grant.in","r",stdin); 35 freopen("grant.out","w",stdout); 36 int a; 37 scanf("%d",&N); 38 for(int i = 2; i <= N; ++i){ 39 scanf("%d",&a); 40 fa[i] = a; 41 } 42 for(int i = N; i > 1; --i) if(!given[i]){ 43 int cur = fa[i]; 44 if(!given[cur]) ans.push_back(i); 45 given[cur] = 1; 46 } 47 printf("%d\n",1000 * (int)ans.size()); 48 if(ans.size()){ 49 printf("%d",ans[ans.size() - 1]); 50 for(int i = ans.size() - 2; i >= 0; --i) printf(" %d",ans[i]); 51 puts(""); 52 } 53 return 0; 54 }
D题:
一道考思维的水题。
初始矩阵A中 a[i][j] 的含义是第 i 个点是否在第 j 条边上,转置矩阵AT中 a'[i][j] 的含义是第 i 条边上是否有第 j 个点。
那么我们可以把AT × A的乘法看做边×边,那么答案中的 a''[i][j] 就表示有多少个点同时出现在第 i 条边和第 j 条边的端点上。
于是 sum(a''[i][j])的含义就是统计每个点在所有边中的出现次数之和。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 25 int N,M; 26 int cnt[10010]; 27 pii edge[100010]; 28 29 int main(){ 30 freopen("matrix.in","r",stdin); 31 freopen("matrix.out","w",stdout); 32 scanf("%d%d",&N,&M); 33 int a,b; 34 REP(i,M){ 35 scanf("%d%d",&a,&b); 36 edge[i] = MP(a,b); 37 cnt[a]++; 38 cnt[b]++; 39 } 40 ll ans = 0; 41 REP(i,M){ 42 ans += cnt[edge[i].first] + cnt[edge[i].second]; 43 } 44 cout << ans << endl; 45 return 0; 46 }
E题:
这场的高精度有点多....
考虑用dp来写,由于N很大,所以考虑矩阵快速幂,一列一列推。
首先枚举第一列,行数最大为M<=5,每个为黑/白,所以第一列最多有32种。
从第 i 列推到第 i+1 列需要保证不会构造出一个颜色相同的 2×2 矩形,根据这个条件构造转移矩阵。
因为N的范围很大,需要上高精度。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int maxn = 100; 25 26 int M,P; 27 int g[40][10],sz; 28 29 struct bign{ 30 int len,s[maxn + 5]; 31 32 //初始化与赋值 33 bign(){ 34 memset(s,0,sizeof(s)); 35 len = 1;//因为0的存在 36 } 37 38 bign operator = (const char *num){ 39 len = strlen(num); 40 memset(s,0,sizeof(s)); 41 for(int i = 0; i < len; ++i) 42 s[i] = num[len - i - 1] - '0';//倒序转化成数字 43 return *this; 44 } 45 46 bign operator = (int num){ 47 char ts[maxn + 5]; 48 sprintf(ts,"%d",num); 49 *this = ts; 50 return *this; 51 } 52 53 bign(int num){ 54 *this = num; 55 } 56 57 bign(const char *num){ 58 *this = num; 59 } 60 //bign的str型转化 61 string str() const{ 62 string res = ""; 63 for(int i = len - 1; i >= 0; --i) 64 res += (char)(s[i] + '0'); 65 if(res == "") 66 res = "0"; 67 return res; 68 } 69 //运算符重载 70 //高精度加 71 bign operator + (const bign & b) const{ 72 bign sum; 73 sum.len = 0; 74 for(int i = 0, g = 0; g || i < max(len,b.len); ++i){ 75 int x = g;//x:暂存和,g:进位 76 if(i < len) x += s[i]; 77 if(i < b.len) x += b.s[i]; 78 sum.s[sum.len++] = x % 10; 79 g = x / 10; 80 } 81 return sum; 82 } 83 84 //高精度减 85 bign operator - (const bign & b) const{ 86 bign dif; 87 int maxlen = (len > b.len) ? len : b.len; 88 for(int i = 0; i < maxlen; ++i){ 89 dif.s[i] += s[i] - b.s[i]; 90 if(dif.s[i] < 0){ 91 dif.s[i] += 10; 92 --dif.s[i + 1]; 93 } 94 } 95 dif.len = maxlen; 96 while(dif.s[dif.len - 1] == 0 && dif.len > 1) 97 --dif.len; 98 return dif; 99 } 100 101 //高精度乘,实际上加和乘对进位的处理有所不同 102 bign operator * (const bign &b) const{ 103 bign pro; 104 pro.len = 0; 105 for(int i = 0; i < len; ++i){ 106 for(int j = 0; j < b.len; ++j){ 107 pro.s[i + j] += (s[i] * b.s[j]); 108 pro.s[i + j + 1] += pro.s[i + j] / 10; 109 pro.s[i + j] %= 10; 110 } 111 } 112 pro.len = len + b.len + 1;//这里注意pro.len初始值可能是题目数字范围两倍 113 while(pro.s[pro.len - 1] == 0 && pro.len > 1) 114 --pro.len;//最后一位不管是不是0都不能让len - 1 115 if(pro.s[pro.len]) 116 ++pro.len;//这句有待商讨 117 return pro; 118 } 119 120 //高精度乘以低精度 121 bign operator * (const int num) const{ 122 int c = 0,t; 123 bign pro; 124 for(int i = 0; i < len; ++i){ 125 t = s[i] * num + c; 126 pro.s[i] = t % 10; 127 c = t / 10; 128 } 129 pro.len = len; 130 while(c != 0){ 131 pro.s[pro.len++] = c % 10; 132 c /= 10; 133 } 134 return pro; 135 } 136 137 //高精度除,模拟连减 138 bign operator / (const bign & b) const{ 139 bign quo,f; 140 for(int i = len - 1; i >= 0; --i){ 141 f = f * 10; 142 f.s[0] = s[i]; 143 while(f >= b){ 144 f = f - b; 145 ++quo.s[i]; 146 } 147 } 148 quo.len = len; 149 while(quo.s[quo.len - 1] == 0 && quo.len > 1) 150 --quo.len; 151 return quo; 152 } 153 154 //比较运算符 155 bool operator < (const bign & b) const{ 156 if(len != b.len) return len < b.len; 157 for(int i = len - 1; i >= 0; --i)//从高位开始比较 158 if(s[i] != b.s[i]) 159 return s[i] < b.s[i]; 160 //如果 本身 == b 161 return false; 162 } 163 164 bool operator > (const bign &b) const{ 165 return b < *this;//代表 本身 > b 166 } 167 168 bool operator <= (const bign &b) const{ 169 return !(b < *this);//带表 !(本身 > b) 170 } 171 172 bool operator >= (const bign &b) const{ 173 return !(*this < b); 174 } 175 176 bool operator != (const bign &b) const{ 177 return *this < b || b < *this; 178 } 179 180 bool operator == (const bign &b) const{ 181 return !(*this < b) && !(b < *this); 182 } 183 184 friend istream & operator >> (istream & in,bign & x); 185 friend ostream & operator << (ostream & out,const bign & x); 186 }N; 187 188 istream & operator >> (istream & in,bign & x){ 189 string ts; 190 in >> ts; 191 x = ts.c_str(); 192 return in; 193 } 194 195 ostream & operator << (ostream & out,const bign & x){ 196 out << x.str(); 197 return out; 198 } 199 200 struct Mx{ 201 int a[40][40]; 202 void clear(){ 203 MEM(a,0); 204 } 205 void stand(){ 206 MEM(a,0); 207 REP(i,sz) a[i][i] = 1; 208 } 209 Mx operator * (Mx &b){ 210 Mx c; c.clear(); 211 REP(k,sz) REP(i,sz) REP(j,sz) 212 c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j] % P) % P; 213 return c; 214 } 215 }t; 216 217 void Trans(int id,int v){ 218 int cur = 0; 219 while(v){ 220 g[id][cur++] = v & 1; 221 v >>= 1; 222 } 223 } 224 225 bool Check(int a,int b){ 226 for(int i = 1; i < M; ++i){ 227 int cur = g[a][i] + g[a][i - 1] + g[b][i] + g[b][i - 1]; 228 if(cur == 0 || cur == 4) return false; 229 } 230 return true; 231 } 232 233 void Build(){ 234 t.clear(); 235 REP(i,sz) REP(j,sz){ 236 if(Check(i,j)) t.a[i][j] = 1; 237 else t.a[i][j] = 0; 238 } 239 } 240 241 Mx Q_pow(bign n){ 242 Mx res; 243 res.stand(); 244 while(n != bign(0)){ 245 if(n.s[0] & 1) res = res * t; 246 t = t * t; 247 n = n / bign(2); 248 } 249 return res; 250 } 251 252 void Solve(){ 253 Build(); 254 Mx ans; 255 ans.clear(); 256 REP(i,sz) ans.a[i][0] = 1; 257 ans = Q_pow(N - bign(1)) * ans; 258 //Debug(ans); 259 ll sum = 0; 260 REP(i,sz) sum = (sum + (ll)ans.a[i][0]) % P; 261 cout << sum << endl; 262 } 263 264 int main(){ 265 freopen("nice.in","r",stdin); 266 freopen("nice.out","w",stdout); 267 cin >> N; 268 cin >> M >> P; 269 sz = 1 << M; 270 REP(i,sz){ 271 Trans(i,i); 272 } 273 Solve(); 274 return 0; 275 }
F题:
这道题补了 2days+ 来补... 虽然很艰难,但收获还是不少的。感谢ztxz16的题解和解答
※船的半径为r,考虑所有岛屿对,如果两个岛屿圆心连线的空隙长度不足以让船通过,则在两个岛屿间建边(无向)
那么容易发现,我们只要判断是否存在一个多边形把船的圆心包含在内即可。
※在图中找所有环是NPC的,但这题只需用dfs树来找简单环(如果大环包含圆心,必有一个简单环包含圆心)。
方法是根据dfs的过程,产生了一颗遍历树,如果发现了一条非树边(即连接树上两个非相邻点的边),那么找出该边两个点的lca,
找lca的路径再加上这条非树边就构成了简单环。
※然后就是判点是否在多边形内的问题了,运用了大白书介绍的转角法。为了提高效率... 我预处理了其中的 winding number。
注意:环要找齐,所以要遍历每一个dfs过的点。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int MAXN = 310; 25 const double eps = 1e-8; 26 27 int N; 28 vector<int> g[MAXN]; 29 int vis[MAXN]; 30 int fa[MAXN],dep[MAXN]; 31 int wn[MAXN][MAXN]; 32 33 struct Point{ 34 double x,y; 35 Point(double tx = 0,double ty = 0) : x(tx) , y(ty) {} 36 friend Point operator - (Point a,Point b){ 37 return Point(a.x - b.x,a.y - b.y); 38 } 39 }; 40 41 struct Circle{ 42 Point c; 43 double r; 44 }C[MAXN]; 45 46 int dcmp(double x){ 47 if(fabs(x) < eps) return 0; 48 return x < 0 ? -1 : 1; 49 } 50 51 double Cross(Point a,Point b){ 52 return a.x * b.y - b.x * a.y; 53 } 54 55 double Dot(Point a,Point b){ 56 return a.x * b.x + a.y * b.y; 57 } 58 59 bool Check_inside(int a,int b){ 60 int cur = wn[a][b]; 61 while(dep[a] > dep[b]){ 62 cur += wn[fa[a]][a]; 63 a = fa[a]; 64 } 65 while(dep[b] > dep[a]){ 66 cur += wn[b][fa[b]]; 67 b = fa[b]; 68 } 69 while(a != b){ 70 cur += wn[fa[a]][a]; 71 cur += wn[b][fa[b]]; 72 a = fa[a]; 73 b = fa[b]; 74 } 75 return cur == 0 ? 0 : 1; 76 } 77 78 double Dis(Point a,Point b){ 79 return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 80 } 81 82 bool Judge(int a,int b){ 83 double d = Dis(C[a].c,C[b].c) - C[a].r - C[b].r; 84 if(d < 2.0 * C[N].r) return 1; 85 return 0; 86 } 87 88 void Dfs(int p,int pre,int s){ 89 vis[p] = 1; 90 fa[p] = pre; 91 dep[p] = s; 92 for(int i = 0; i < g[p].size(); ++i){ 93 int v = g[p][i]; 94 if(v == pre) continue; 95 if(vis[v]){ 96 if(Check_inside(p,v)){ 97 printf("NO\n"); 98 exit(0); 99 } 100 } 101 else Dfs(v,p,s + 1); 102 } 103 } 104 105 int main(){ 106 freopen("out.in","r",stdin); 107 freopen("out.out","w",stdout); 108 scanf("%d",&N); 109 REP(i,N) scanf("%lf%lf%lf",&C[i].c.x,&C[i].c.y,&C[i].r); 110 scanf("%lf%lf%lf",&C[N].c.x,&C[N].c.y,&C[N].r); 111 REP(i,N) FOR(j,i + 1,N - 1) if(Judge(i,j)){ 112 g[i].push_back(j); 113 g[j].push_back(i); 114 } 115 Point p = C[N].c; 116 REP(i,N) REP(j,N) if(i != j){ 117 Point t1 = C[i].c,t2 = C[j].c; 118 int k = dcmp(Cross(t2 - t1,p - t1)); 119 int d1 = dcmp(t1.y - p.y); 120 int d2 = dcmp(t2.y - p.y); 121 if(k > 0 && d1 <= 0 && d2 > 0) wn[i][j] = 1; 122 if(k < 0 && d1 > 0 && d2 <= 0) wn[i][j] = -1; 123 } 124 REP(i,N) if(!vis[i]) Dfs(i,-1,0); 125 printf("YES\n"); 126 return 0; 127 }
G题:
以前做过的题目...
其实我们的任务就是找到一个最长的序列,使得前一个人的S值和B值均比后一个人大。
按照S升序排序,S相同的按照B降序排序。然后再找出B的最长上升子序列即可(思考),这样就能保证题目的要求!
由于S、B的值范围过大,离散化一下,然后套个树状数组(线段树)即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 #define X first 21 #define Y second 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 const int MAXN = 100010; 27 28 int N; 29 int pre[MAXN]; 30 int b[MAXN]; 31 32 struct node{ 33 int S,B; 34 int id; 35 }nd[MAXN]; 36 37 bool cmp(node a,node b){ 38 if(a.S == b.S) 39 return a.B > b.B; 40 return a.S < b.S; 41 } 42 43 struct BIT{ 44 pii c[MAXN]; 45 void clear(){ 46 MEM(c,0); 47 } 48 int lowbit(int x){ 49 return x & (-x); 50 } 51 void update(int x,int d,int id){ 52 while(x <= N){ 53 if(c[x].X < d){ 54 c[x] = MP(d,id); 55 } 56 x += lowbit(x); 57 } 58 } 59 pii getmax(int x){ 60 pii res(0,0); 61 while(x){ 62 if(c[x].X > res.X) res = c[x]; 63 x -= lowbit(x); 64 } 65 return res; 66 } 67 }bt; 68 69 void Print(int p){ 70 if(pre[p] == 0) printf("%d",nd[p].id); 71 else{ 72 Print(pre[p]); 73 printf(" %d",nd[p].id); 74 } 75 } 76 77 int main(){ 78 freopen("people.in","r",stdin); 79 freopen("people.out","w",stdout); 80 scanf("%d",&N); 81 FOR(i,1,N){ 82 scanf("%d%d",&nd[i].S,&nd[i].B); 83 b[i] = nd[i].B; 84 nd[i].id = i; 85 } 86 sort(nd + 1,nd + N + 1,cmp); 87 sort(b + 1,b + N + 1); 88 int sz = unique(b + 1,b + N + 1) - b; 89 FOR(i,1,N) nd[i].B = lower_bound(b + 1,b + N + 1,nd[i].B) - b; 90 bt.clear(); 91 int tmax = 0,pos = 0; 92 FOR(i,1,N){ 93 pii cur = bt.getmax(nd[i].B - 1); 94 bt.update(nd[i].B,cur.X + 1,i); 95 if(cur.X + 1 > tmax){ 96 tmax = cur.X + 1; 97 pos = i; 98 } 99 pre[i] = cur.Y; 100 } 101 printf("%d\n",tmax); 102 Print(pos); 103 puts(""); 104 return 0; 105 }
H题:
比赛时没做出来的一题...
正解是高斯消元求解的个数,很精巧~
首先将所有数素数分解,由于我们要从数的集合取出一些数使得他们的和为完全平方数,那么其实就是
他们对应的分解后的素数指数和为偶数,那么我们列出方程组,以各个素数为行,集合中的各个数为列。
系数为集合中每个数分解后的素数指数,x 可以取0或1(代表这个数取不取)
高斯消元后求出自由元的个数 cnt,解的个数就为 2^(cnt),注意要去掉空集,所以答案是 2^(cnt) - 1
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int MAXN = 110; 25 26 int t,m; 27 int v[MAXN]; 28 int g[MAXN][MAXN]; 29 bool check[1000]; 30 int prime[MAXN],pcnt; 31 32 void Pre(){ 33 pcnt = 0; 34 for(int i = 2; pcnt < 100; ++i) if(!check[i]){ 35 prime[++pcnt] = i; 36 for(int j = i + i; j < 1000; j += i) 37 check[j] = true; 38 } 39 } 40 41 int Gauss(){ 42 int cnt_free = 0; 43 int equ = t; 44 for(int i = 1,col = 1; col <= m; ++i,++col){ 45 int cur = i; 46 for(int j = i + 1; j <= equ; ++j) if(g[j][col]){ 47 cur = j; 48 break; 49 } 50 if(cur != i) 51 for(int j = col; j <= m; ++j) swap(g[i][j],g[cur][j]); 52 if(g[i][col] == 0){ 53 cnt_free++; 54 --i; 55 continue; 56 } 57 for(int k = i + 1; k <= equ; ++k) if(g[k][col]){ 58 for(int j = col; j <= m; ++j) 59 g[k][j] ^= g[i][j]; 60 } 61 } 62 return cnt_free; 63 } 64 65 void Print(int cnt){ 66 int s[1000] = {0}; 67 int len = 1; 68 s[1] = 1; 69 REP(o,cnt){ 70 int t,c = 0; 71 FOR(i,1,len){ 72 t = s[i] * 2 + c; 73 s[i] = t % 10; 74 c = t / 10; 75 } 76 if(c) s[++len] = c; 77 } 78 int c = -1; 79 FOR(i,1,len){ 80 s[i] += c; 81 if(s[i] < 0) s[i] = 9; 82 else break; 83 } 84 int pos = len; 85 while(s[pos] == 0) len--; 86 for(int i = pos; i >= 1; --i) printf("%d",s[i]); 87 puts(""); 88 } 89 90 int main(){ 91 freopen("rsa.in","r",stdin); 92 freopen("rsa.out","w",stdout); 93 Pre(); 94 scanf("%d%d",&t,&m); 95 FOR(i,1,m){ 96 scanf("%d",v + i); 97 for(int j = 1; j <= t; ++j) if(v[i] % prime[j] == 0){ 98 int cnt = 0; 99 while(v[i] % prime[j] == 0){ 100 cnt++; 101 v[i] /= prime[j]; 102 } 103 g[j][i] = cnt % 2; 104 } 105 } 106 int cnt = Gauss(); 107 Print(cnt); 108 return 0; 109 }