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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

posted @ 2015-04-10 21:30  Naturain  阅读(366)  评论(0编辑  收藏  举报