A. Johnny and Ancient Computer(因子拆分)
分析
- 題意
- 給我們兩個數a、b,現在我們我們可以對 a來了進行一些系列的x2 、x4、 x8、 /2 、/4、 /8 等運算操作,問我們通過一些這樣的操作以後能否把a變成b,如果能輸出需要的最小次數,否則輸出-1
- 分析
- 這個題中既可能有乘法 又有 除法操作,我們可能 在輸入a、b的之後,如果 a < b的話,我們交換二者的值,令a始終保持較大值,這樣我們只需要對a進行 除法操作了,如果 對a進行 /2 /4 /8的操作之後要想得到最終結果 a == b ,那我們可以令c = a / b(這裏要確保 a % b == 0),這樣我們依次從c中拆分出儘可能多的 8、在拆分儘可能多的4、最後拆分出儘可能對2 ,這樣拆分完之後如果剩下的數不是1的話,直接輸出-1,否則的話答案就是拆分出 8,4,2的總共數量
代碼
#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353
int br[10];
int ar[5];
int main()
{
/* fre(); */
int T;
scanf("%d\n", &T);
ar[1] = 8, ar[2] = 4, ar[3] = 2;
while(T --)
{
ll a, b;
scanf("%lld %lld", &a, &b);
if(a < b) swap(a, b);
if(a % b)
{
printf("-1\n");
continue;
}
ll c = a / b;
memset(br, 0, sizeof(br));
for(int i = 1; i <= 3; i ++)
{
while(c % ar[i] == 0)
{
c /= ar[i];
br[ar[i]] ++;
}
}
if(c != 1)
{
printf("-1\n");
continue;
}
printf("%d\n", br[2] + br[4] + br[8]);
}
return 0;
}
B. Johnny and His Hobbies(暴力)
分析
- 題意
- 給我們s個數讓我們照出一個最小正整數k,是s個數都 異或k 得到的值形成一個集合a,要求a與s中所包含的元素完全相同,求這個k
- 分析
- 由於數據範圍比較小,我們直接暴力求解k的最合適值
代碼
#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e3 + 100;
int ar[mxn];
int br[mxn];
int cr[mxn];
int main()
{
/* fre(); */
int T;
scanf("%d\n", &T);
while(T --)
{
memset(br, 0, sizeof(br));
int n;
scanf("%d\n", &n);
for(int i = 1; i <=n; i ++)
scanf("%d", &ar[i]), br[ar[i]] = 1;
int ans = 0;
for(int i = 1; i <= 1024; i ++)
{
memset(cr, 0, sizeof(cr));
int fg = 1;
for(int j = 1; j <= n; j ++)
{
int t = (ar[j] ^ i);
if(++ cr[t] >= 2)
{
fg = 0;
break;
}
}
if(fg == 0)
continue;
for(int j = 0; j <= 1024; j ++)
{
if(br[j] != cr[j])
{
fg = 0;
break;
}
}
if(fg)
{
ans = i;
break;
}
}
if(ans == 0)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}
C. Johnny and Another Rating Drop
分析
- 分析
000
001
010
011
100
101
- 因爲二進制是逢二進一,所以我們依次觀察二進制的最地位到高位發現,
- 對於 二進制值倒數第1位,這一位對答案的貢獻是 n
- 對與 二進制的倒數第2位,這一位對答案的貢獻是 n / 2
- 對於 二進制的倒數第3位,這一位對答案的貢獻是 n / 4
- 綜上 二進制的倒數第i位,對答案的貢獻是 ,
- 所以 答案 ans = n/1 + n/2 + n/4 …
- 還有一種方法也是規律,規律是:2*n - 二進制中1的數量 =ans,,,這個規律爲什麼對,我也無法解釋,但 確實ac了
代碼一
#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e6 + 100;
int main()
{
/* fre(); */
int T;
scanf("%d", &T);
while(T --)
{
ll n, i = 1, ans = 0;
scanf("%lld\n", &n);
ll now = n;
while(now)
{
ans += n / i;
i *= 2;
now >>= 1;
}
printf("%lld\n", ans);
}
return 0;
}
代碼二
#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e3 + 100;
int main()
{
/* fre(); */
int T;
scanf("%d\n", &T);
while(T --)
{
ll n, t;
scanf("%lld", &n);
t = n;
ll ct = 0;
while(n)
{
if(n & 1) ct ++;
n >>= 1;
}
printf("%lld\n", t * 2 - ct);
}
return 0;
}
D. Johnny and Contribution(模擬+貪心)
分析
- 題意
- 給我們一個有n個節點m邊的無向圖,每個節點有一個 1~n的目標權值,然後我們對每個節點進行染色(給這個節點賦上一個 1~n的權值),對於某個節點我要染色的規則是,與當前節點相鄰的節點中沒有出現過的顏色(權值數字)中最小的那個權值數字我賦值給當前的 節點,通過這樣的染色操作之後,如果每個節點的新權值與 目標權值都先相同的話,輸出染色節點的順序,否則輸出-1
- 分析
- 貪心,易得我們應該按照期望從小到大塗色,首先我們包期望爲1的節點u都塗掉,然後判斷與其直接相連的節點v 如果如果它的期望也爲1,我們就把v的期望顏色++,
- 以此類推,因爲是從小開始塗顏色的,所以保證比當前u顏色小的節點都塗過顏色了,接着我就直接判斷,只要當前節點u的期望不是原來的顏色,我們就可以直接返回-1,最後 注意一下初始化期望顏色爲1
代碼
#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e6 + 100;
vector<int> e[mxn];
vector<int> col[mxn];
vector<int> ans;
int num[mxn];
int main()
{
/* fre(); */
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1, u, v; i <= m; i ++)
{
scanf("%d %d", &u, &v);
e[u].pb(v);
e[v].pb(u);
}
for(int i = 1, t; i <= n; i ++)
{
scanf("%d", &t);
col[t].pb(i);
num[i] = 1; //初始的時候,每個節點周圍只有一個 自己1個節點
}
for(int i = 1; i <= n; i ++)
{
for(auto u : col[i])
{
if(num[u] != i) printf("-1\n"), exit(0);
for(auto v : e[u])
if(num[v] == i) num[v] ++;
ans.pb(u);
}
}
for(auto i : ans) printf("%d ", i);
return 0;
}