目录
A. Johnny and Ancient Computer
C. Johnny and Another Rating Drop
A. Johnny and Ancient Computer
题意:给定两个数A,B,问A能不能不断通过乘或除2、4、8(能整除才能除),得到B
思路:如果A能得到B,B也能得到A,所以AB的大小关系假定为A大B小。如果A不能整除B,则不可能得到B,否则计算出AB倍数,为了让步数最小先除8再除4再除2,如果最后剩的数非1,则也不能得到B。
AC代码:
/*---------------------------------
*File name: A.cpp
*Creation date: 2020-06-05 09:18
*Link:https://codeforces.com/contest/1362/problem/A
*-------------------------------*/
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int>
#define Pque priority_queue
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;
int main(){
int t;
scanf("%d", &t);
while(t--){
LL a , b;
scanf("%lld %lld", &a, &b);
LL ans = 0;
if(a < b) swap(a, b);
if(a % b != 0) printf("-1\n");
else {
LL times = a / b;
while(times % 8 == 0) times /= 8, ans++;
while(times % 4 == 0) times /= 4, ans++;
while(times % 2 == 0) times /= 2, ans++;
if(times != 1) printf("-1\n");
else printf("%lld\n", ans);
}
}
return 0;
}
B. Johnny and His Hobbies
题意:给定n个各不相同的数集,问能不能选择一个K,使得每个数异或K之后的数集与原数集相同(顺序可以不同)。
思路:暴力直接做,从小到大枚举K,异或的结果与原数集比较。
AC代码:
/*---------------------------------
*File name: B.cpp
*Creation date: 2020-06-05 09:18
*Link:https://codeforces.com/contest/1362/problem/B
*-------------------------------*/
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int>
#define Pque priority_queue
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;
int main(){
int t;
scanf("%d", &t);
while(t--){
int n;
scanf("%d", &n);
set<int> s;
map<set<int>, bool> mp;
for(int i = 0; i < n; ++i){
int a ;
scanf("%d", &a);
s.insert(a);
}
mp[s] = 1;
bool flag = 0;
for(int i = 1; i <= 2000; ++i){
set<int> :: iterator it;
set<int> c;
for(it = s.begin(); it != s.end(); ++it){
c.insert((*it) ^ i);
}
if(mp[c] == 1){
printf("%d\n", i);
flag = 1;
break;
}
}
if(!flag) printf("-1\n");
}
return 0;
}
C. Johnny and Another Rating Drop
题意:给一个N,问二进制下0~N的所有数中相邻的数的二进制同一位不同的个数和。如0101和1110有3个数位不同。
思路:这一位每一位相邻的数都不一样,对答案的贡献为N,这一位每两位对答案贡献位1...类推,当N有cnt位二进制位的时候,每对答案贡献为1,所以计算出N有多少位二进制,然后算每一位对答案的贡献就行了。
AC代码:
/*---------------------------------
*File name: C.cpp
*Creation date: 2020-06-05 09:18
*Link:https://codeforces.com/contest/1362/problem/C
*-------------------------------*/
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int>
#define Pque priority_queue
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;
LL fpow(LL x, LL y){
LL ans = 1;
while(y){
if(y & 1) ans = ans * x;
x *= x;
y >>= 1;
}
return ans;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
LL n;
scanf("%lld", &n);
int cnt = 0;
LL tmp = n;
while(tmp) cnt++, tmp >>= 1;
//n++;
LL ans = 0;
for(int i = 0; i < cnt; ++i){
ans += n / fpow(2, i);
}
printf("%lld\n", ans);
}
return 0;
}
D. Johnny and Contribution
题意:Jony要写n篇博客,每篇博客的内容只能覆盖一个主题,但一个主题可以被多篇博客覆盖。在博客与博客之间可以相互引用,但是相互引用的博客不能涵盖相同的主题,否则博客是无效的。给出Jony要写的博客之间的相互引用关系,他在写博客的时候会依照这个引用关系来安排写博客的顺序,因此他在写博客的时候会首先查看他要引用的博客的主题,然后选出没有被覆盖的且主题编号最小的主题写入本篇博客。例如:若要的这篇博客引用的博客覆盖了主题1,3,2,5,那么这篇博客就应该要选择主题4编写。问是否存在一个写博客的顺序满足博客之间的相互引用。
思路:题意精简之后就是有N个点M条边,每个点有特定属性Ti,对于任意一点u,与u直接相连的所有点中不能有与点u属性相同的点,并且直接相连的点的属性必须存在1~-1的所有数。那么首先比较简单的可以判断的是与u直接相连的点中是否存在属性一样的点,只要记录下所有点的属性值就可以。第二个要判断的是是否存在1~-1在与点u相连的点中,只需要将与点u相连的点的属性放到set里,然后1~-1去查询就可以了。如果这两个条件都满足,则就可以安排出顺序。但是由于具体的安排需要的是:对于当前要安排的位置P,要求是1~P-1中与安排在这个位置的点u相连的点中不能有重复属性且必须1~ - 1全都出现,所以可以sort升序排序属性值,根据属性值从小到大安排,这样只要满足以上两个条件,此安排就必定可行。
AC代码:
/*---------------------------------
*File name: C.cpp
*Creation date: 2020-06-05 09:18
*Link:https://codeforces.com/contest/1362/problem/C
*-------------------------------*/
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int>
#define Pque priority_queue
using namespace std;
const int maxn = 5e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;
int head[maxn], tot = -1;
struct Edge{
int v, next;
void Add_Edge(int u, int v){
this -> v = v;
this -> next = head[u];
head[u] = tot;
}
}edge[maxn << 1];
struct Node{
int T;
int num;
friend bool operator < (Node x, Node y){
return x.T < y.T;
}
}t[maxn];
int pt[maxn];
int main(){
int n, m;
scanf("%d %d", &n, &m);
memset(head, -1, sizeof(head));
for(int i = 1; i <= m; ++i){
int a, b;
scanf("%d %d", &a, &b);
edge[++tot].Add_Edge(a, b);
edge[++tot].Add_Edge(b, a);
}
for(int i = 1; i <= n; ++i) {
scanf("%d", &t[i].T);
pt[i] = t[i].T;
t[i].num = i;
}
sort(t + 1, t + 1 + n);
bool flag = 1;
for(int i = 1; i <= n; ++i){
set<int> s;
int u = t[i].num;
for(int j = head[u]; j != -1; j = edge[j].next){
s.insert(pt[edge[j].v]);
if(pt[u] == pt[edge[j].v]){
flag = 0;
break;
}
}
if(!flag) break;
int cnt = 0;
while(++cnt < pt[u]){
if(s.find(cnt) == s.end()){
flag = 0;
break;
}
}
if(!flag) break;
}
if(!flag) printf("-1\n");
else{
for(int i = 1; i <= n; ++i) printf("%d%c", t[i].num, i == n ? '\n' : ' ');
}
return 0;
}