CODEFORCES ROUND #628 (DIV. 2)
AB日常划水
C题
https://codeforces.ml/contest/1325/problem/C
题目真的容易误解,特别是因为昨天写过博弈论,里面也有mex函数我就以为这个和那个意思差不多|虽然确实差不多
You are given a tree consisting of nn nodes. You want to write some labels on the tree's edges such that the following conditions hold:
- Every label is an integer between 00 and n−2n−2 inclusive.
- All the written labels are distinct.
- The largest value among MEX(u,v)MEX(u,v) over all pairs of nodes (u,v)(u,v) is as small as possible.
Here, MEX(u,v)denotes the smallest non-negative integer that isn't written on any edge on the unique simple path from node uu to node vv.Input
The first line contains the integer n (2≤n≤105) — the number of nodes in the tree.
Each of the next n−1lines contains two space-separated integers u and v (1≤u,v≤n1≤u,v≤n) that mean there's an edge between nodes u and v. It's guaranteed that the given graph is a tree.Output
Output n−1n−1 integers. The ithith of them will be the number written on the ithith edge (in the input order).
题目大意:输入n有n条边,下面n行,每行有a,b代表a,b连一条边问你min(max(mex(u,v))是多少mex(u,v)是 不在 u到v的简单路径中的 其他边的最小整数
mex1,6就是 2,4 1,3这两条边权值的min (2)
显然一条链(出入度为2)的情况答案肯定是n-2
先假设有一个出入度为三的点 a,假设边值为0,1,2,因为会枚举到所有点,如果不经过a则mex =0,如果经过a max mex=2 即不能同时经过和这个点相连的三条边
现在假设有两个不相连的入度为3的点,因为要max mex 最小,所以那两个点边权赋值应该是0,1,2,3,4,5,此时min max mex =5
现在有两个相连的入度为3的点,那肯定赋值0,1,2,3,4 min max mex=4,由此可见我们应该先给入度为3的点的边赋值,其他的点随便分配都可以上面证明不太严谨,我也是看题解yy的啊
就是打map的时候手抽定义了hash关键字出来,搞得我ce半天
make_pair 可以自动辨别所make值的类型返回一个pair类型
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<vector> #include<map> #include<set> #include<utility> using namespace std; const int N=2e5+5; int n,x,y,in[N],tot,ans[N]; vector <int> f[N]; map < pair <int ,int > ,int> d; int main() { scanf("%d",&n); memset(ans,-1,sizeof(ans)); for(int i=1;i<n;i++) { scanf("%d %d",&x,&y); f[x].push_back(y); f[y].push_back(x); d.insert(make_pair(make_pair(x,y),i)); d.insert(make_pair(make_pair(y,x),i)); in[x]++; in[y]++; //printf("%d\n",hash[make_pair(y,x)]); } for(int i=1;i<=n;i++) { if(in[i]>=3) { for(int j=0;j<f[i].size();j++) { int temp=f[i][j]; if(ans[d[make_pair(i,temp)]]==-1) { ans[d[make_pair(i,temp)]]=tot; tot++; } } } } for(int i=1;i<=n;i++) { for(int j=0;j<f[i].size();j++) { int temp=f[i][j]; if(ans[d[make_pair(i,temp)]]==-1) { ans[d[make_pair(i,temp)]]=tot; tot++; } } } for(int i=1;i<n;i++) { printf("%d\n",ans[i]); } return 0; }
D题
https://codeforces.ml/contest/1325/problem/D
这么短的题就自己读一下吧...
u=a xor b,v=a+b,a,b为非负整数
显然v<u的时候是无解的因为v=a+b=u+2∗(a&b)(a&b>=0)
异或的性质1: x xor 0 =x 所以u==v的时候 可以构造出0,u满足条件(0,0特判)这时输出1\n u\n(因为说了输出只有正整数)
根据上面的性质可继续推 x xor y xor y= x 所以 猜测x =u,2*y+x=v
所以y=a&b=(u-v)/2,if u-v%2!=0也无解
否则因为一定存在 这样的x,y满足题意,所以最大长度是3(x,y,y)
现在枚举一下x,y两两组合看能不能满足题意就好了 (就是看(x+y)xor y和x xor 2*y 满不满足就可以了
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; long long u,v; int main() { scanf("%lld %lld",&u,&v); if(v<u) printf("-1\n"); if(v==u) { if(u==0) printf("0\n"); else printf("1\n%lld\n",u); } if(v>u) { if((v-u)%2) printf("-1\n"); else { long long b=(v-u)/2; if((u^(v-u))==u) printf("2\n%lld %lld\n",u,v-u); else if(((u+b)^b)==u) printf("2\n%lld %lld\n",u+b,b); else printf("3\n%lld %lld %lld",u,b,b); } } return 0; }
记得开longlong和0,0特判
E题
https://codeforces.ml/contest/1325/problem/E
You are given an array aa of length nn that has a special condition: every element in this array has at most 7 divisors. Find the length of the shortest non-empty subsequence of this array product of whose elements is a perfect square.
A sequence aa is a subsequence of an array bb if aa can be obtained from bb by deletion of several (possibly, zero or all) elements.Input
The first line contains an integer n (1≤n≤10^5) — the length of aa.
The second line contains nn integers a1, a2, ……, an (1≤ai≤10^6) — the elements of the array aa.Output
Output the length of the shortest non-empty subsequence of aa product of whose elements is a perfect square. If there are several shortest subsequences, you can find any of them. If there's no such subsequence, print "-1".
题目大意:给你n个数,a1,a2,...an,保证ai的约数个数小于7,让你从这n个数中选取最少的数 是他们相乘结果为完全平方数,输出最小 选取数的个数
可以证明约数个数小于7则分解质因数后肯定小于3个不同质因数,(1,p,q,w,qp,qw,pw,pqw 八个了)如果有相同的质因数,处理一下,把偶数次幂去掉(对结果没有影响可以直接无视),最后剩下奇数次幂的质因数肯定也最多只有两个,我们可以构造一个图(不一定连通),节点就是质因数,
如果节点被连了几边说明几个数中有这个质因数,我们只要找到一条路径,这条路上的点全是偶数条边即可(这个路径肯定是环),因为如果选的节点不构成一个环,则末尾节点肯定是奇数,所以我们只要枚举每一个点找出这个图中的最小环就行了
但是枚举每一个点肯定超时,想到 求因数的优化方法,我们可以类推到如果一个因数大于sqrt max ai 的节点q,则它肯定连着小于sqrt max ai 的节点p,因为我们是按顺序枚举的,枚举p的时候肯定就q情况判断出来了,就不用再枚举q了。
建图:
1 如果是因数是q,p, 则pq连一条边 (p-q)
2 如果因数只有p 则p-1
3 如果只有1 或他本身就是完全平方数 直接输出 1
4 如果除了3还有重复的数输出 2
数字预处理真的难搞
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<vector> #include<map> #include<queue> #include<set> #include<utility> #include<cmath> using namespace std; const int N=2e5+5,M=1e6+5,inf=2147483647; int n,x,dis[M],a[M],ss[M],k,tot,ans=inf; bool use[M]; vector <int> g[M]; queue <int> q; set < int > s1,s2; void bfs(int x) //找最小环 { for (auto i:s2) dis[i]=inf,use[i] = 0; while(!q.empty()) q.pop(); memset(use,0,sizeof(use)); dis[x]=0; q.push(x); use[x]=1; while (!q.empty()) { int top = q.front(); q.pop(); use[top] = false; for (auto i:g[top]) { if (dis[i] > dis[top] + 1) { dis[i] = dis[top] + 1; q.push(i); use[i] = true; } else if (use[i]) { ans = min(ans, dis[top] + dis[i] + 1); } } } } int init(int x) //初步化简掉偶数次幂的因数 { for (int i = 2; i * i <= x; ++i) { if (x % i) continue; int cnt = 0; while (x % i == 0) x /= i, ++cnt; if (cnt & 1) x *= i; } return x; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&x); x=init(x); s1.insert(x); } if(s1.count(1)==1) { printf("1\n"); return 0; } if(int(s1.size())<n) { printf("2\n"); return 0; } for (auto i : s1)//枚举化简后数的因数 { int tmp[2]; tmp[0]=tmp[1]=-1; tmp[0] = i; for (int j = 2; j * j <= i; ++j) { if (i % j) continue; tmp[0] = j; i /= j; if (i != 1) tmp[1] = i; break; } if (tmp[1] == -1) tmp[1] = 1; for (auto j : tmp) s2.insert(j);//将每个节点放入集合中之后好枚举 g[tmp[0]].emplace_back(tmp[1]); g[tmp[1]].emplace_back(tmp[0]); } //因为如果节点大于sqrt(max ai)肯定只会被连一条边(奇数),就和公因数i*i<j类似 //肯定不会成环直接排除,所以从2~1000里面选节点 for(int i=2;i<=1000;i++) { if(s2.count(i)==0) continue; bfs(i); } if(ans==inf) ans=-1; printf("%d\n",ans); return 0; }