Codeforces Round #647 (Div. 2) - Thanks, Algo Muse!
codeforces-1362-A. Johnny and Ancient Computer
题意:
给你两个数a,b问是否可以通过*2 *4 *8 /2 /4 /8 把a变成b
思路:
因为是*2 *4 *8 /2 /4 /8 乘和除一起组合是没必要的,所以就是a大的话,通过除变成b,a小的话只能通过乘变成b
以乘为例,*4就等于乘了2个2,*8就相当于乘了3个2,所以YES的前提是大的要能被小的整除且除完的数是2的幂次
得到这个幂次之后优先分配给8 其次是4 2 计算总数就可以了
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(a) ((a)&-(a))
#define clean(a,b) memset(a,b,sizeof(a))
const int mod = 1e9 + 7;
const int inf=0x3f3f3f3f;
const int maxn = 2e5+9;
int _;
//========================================================================
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
ll a,b,cnt=0,flag=0,now;
scanf("%lld%lld",&a,&b);
if(a%2&&a>b||b%2&&b>a)
{
puts("-1");
continue;
}
if(a>=b)
{
ll c=a/b;
if(a%b==0)
{
cnt=0,now;
for(int i=0;i<=63;i++)
{
if(((c>>i)&1)==1) cnt++,now=i;
}
}
if(a%b!=0||cnt>=2) flag=1;
}
else
{
ll c=b/a;
if(b%a==0)
{
cnt=0,now;
for(int i=0;i<=63;i++)
{
if(((c>>i)&1)==1) cnt++,now=i;
}
}
if(b%a!=0||cnt>=2) flag=1;
}
if(flag) puts("-1");
else
{
int ans=0;
ans+=now/3;
now%=3;
ans+=now/2;
now%=2;
ans+=now;
printf("%d
",ans);
}
}
return 0;
}
codeforces-1362-B. Johnny and His Hobbies
题意:
给你一个集合,问是是否有一个数,与这个集合异或后形成的新集合相等
思路:
是不是一直在找异或前后的关系,是不是没有找到什么规律,找到了也写的乱七八糟
对,别写了,这题暴力,这个数最大的可能是1024,就枚举这1024个数就行了,惊不惊喜意不意外,我也挺意外的
也不知道之前咋算的一直觉得暴力是1e9的复杂度
很久很久了才看到 “It is guaranteed that the sum of n over all test cases will not exceed 1024.”
然后也没反应过来是排个序直接看是不是相等,太憨了,好好的cf打的稀巴烂,心态崩了还打个p了
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(a) ((a)&-(a))
#define clean(a,b) memset(a,b,sizeof(a))
const int mod = 1e9 + 7;
const int inf=0x3f3f3f3f;
const int maxn = 2e5+9;
int _;
//========================================================================
int a[1500],b[1500];
int main()
{
for(scanf("%d",&_);_;_--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
int flag=0;
for(int i=1;i<=1024;i++)
{
for(int j=1;j<=n;j++)
{
b[j]=a[j]^i;
}
sort(b+1,b+1+n);
int cnt=0;
for(int j=1;j<=n;j++)
{
if(a[j]==b[j]) cnt++;
}
if(cnt==n)
{
flag=i;
break;
}
}
if(flag==0)
{
puts("-1");
}
else
{
printf("%d
",flag);
}
}
return 0;
}
codeforces-1362-C. Johnny and Another Rating Drop
题意:
给你一个数字(n),现在把(0)~(n)全部化成二进制,相邻之间的位数不同的相加后得到的数是多少
思路:
感觉是好写的
一看就是有规律啊,打个表就明白了
1 1
2 3
3 4
4 7
5 8
6 10
7 11
8 15
9 16
10 18
11 19
12 22
13 23
14 25
15 26
16 31
17 32
18 34
19 35
20 38
21 39
22 41
23 42
24 46
25 47
26 49
27 50
28 53
29 54
30 56
31 57
32 63
33 64
他与前一项的差是 1 ((2^{0})) | 2((2^{1})) | 1 3((2^{2})) | 1 2 1 4((2^{3})) | 1 2 1 3 1 2 1 5((2^{4})) | 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6((2^{5}))
然后我们发现,每一段以(k)为结尾的那一整段的和是(2^{k-1}) ,且(k)这个数都是数列的第(2^{k-1})项,包括(k)在内的从(1)~(k)的和是(2^{k}-1,)所以预处理出一个(2)的幂次的序列,每次二分查找要求的(n)在哪段,然后算这段的答案,再从(n)里把这段长度剪掉,循环的处理,直到长度为(0)
我看有的大佬找到规律是 ans[x]=x+ans[x/2],递归处理,妙!
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(a) ((a)&-(a))
#define clean(a,b) memset(a,b,sizeof(a))
const int mod = 1e9 + 7;
const int inf=0x3f3f3f3f;
const int maxn = 2e5+9;
int _;
//========================================================================
vector<ll>ve;
ll getid(ll x) { return upper_bound(ve.begin(), ve.end(), x) - ve.begin() ; }
int main()
{
for(int i=0;i<=63;i++)
{
ve.push_back((1ll<<i));
}
// for(int i=0;i<100;i++) printf("%d %lld
",i,ve[i]);
for(scanf("%d",&_);_;_--)
{
ll n,ans=0;
scanf("%lld",&n);
while(n)
{
ll k=getid(n);
ans+=(1ll<<(k))-1;
n-=(1ll<<(k-1));
}
printf("%lld
",ans);
}
return 0;
}
D没看懂
codeforces-1362-E. Johnny and Grandmaster
题意:
一个长度为n的序列k , 将这些数分为两个集合A、B,使得两个集合差值的绝对值最小
思路:
这个题难就难在他的范围很大,平常的方法计算的时候是存不下的
正常的思路应该是:按从大到小排序,先往a里放一个,然后往b里放,直到超过a了再往a里放,这样才能保证差最小
但问题就是我们(k^{p_{i}})实在是太大了,没法判断是一个集合大于还是小于另一个集合,我也是在这里瞎写了一个然后wa4
其实再仔细审审题,(k^{p_{i}})不能给你就是为了把数扩大的呀,根据(类似于2进制吧)的规则,你从大到小排序之后,b集合的和想大于a集合,他首先要和a集合相等!!!!
对吧,我们只要判断是不是相等就行了,先往a里放,相等了就往b里放,然后继续往a里放……
只用他给的模数1e9+7误差就太大了,我们再多来几个模数对他取模,如果这些模数的结果都为0才是相等
我用的998244353还wa到了44……,这个就凭运气吧
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(a) ((a)&-(a))
#define clean(a,b) memset(a,b,sizeof(a))
const int mod = 1e9 + 7;
const int inf=0x3f3f3f3f;
const int maxn = 1e6+9;
int _;
//========================================================================
ll a[maxn];
int cmp(ll a,ll b)
{
return a>b;
}
ll fpow(ll a,ll b,int c)
{
a%=c;
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%c;
a=a*a%c;
b>>=1;
}
return ans%c;
}
//========================================================================
int main()
{
for(scanf("%d",&_);_;_--)
{
int n,p;
scanf("%d%d",&n,&p);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
sort(a+1,a+1+n,cmp);
ll sum=0,sum_=0;
int mod_=100001651;
int i=1;
while(i<=n)
{
if(sum_==0&&sum==0)
{
sum=(sum+fpow(p,a[i],mod))%mod;
sum_=(sum_+fpow(p,a[i],mod_))%mod_;
i++;
}
if(i>n) break;
sum=(sum-fpow(p,a[i],mod)+mod)%mod;
sum_=(sum_-fpow(p,a[i],mod_)+mod_)%mod_;
i++;
}
printf("%lld
",sum);
}
return 0;
}