AtCoder Beginner Contest 172 题解
A - Calc
程序如下(真的有人需要嘛):
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int a;
cin>>a;
cout<<a+a*a+a*a*a<<endl;
return 0;
}
B - Minor Change
程序如下(应该没人需要吧):
#include<bits/stdc++.h>
using namespace std;
string s,t;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>s>>t;
int ans=0;
for(int i=0;i<s.size();i++)ans+=s[i]!=t[i];
cout<<ans<<endl;
return 0;
}
C - Tsundoku
感性地理解,你在A桌上看的书越多,你在B桌上看的书越少。也就是说,你在A桌上每多看一本书,你在B桌上就要放下一些书。
维护A、B桌看的书的本数。从小到大枚举A桌看的书的本数,B桌看的书的本数就会递减。这个就是传说中的two pointers,然后程序就好写了。
程序如下:
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
int a[200005],b[200005];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
long long tot=0;
for(int i=1;i<=m;i++){
cin>>b[i];
tot+=b[i];
}
int ans=0;
for(int ia=0,ib=m;ia<=n;ia++){
tot+=a[ia];
while(tot>k&&ib>0)tot-=b[ib--];
if(tot>k)break;
ans=max(ans,ia+ib);
}
cout<<ans<<endl;
return 0;
}
D - Sum of Divisors
正着想,从(1)到(N)枚举,求出一个数的质因数个数然后乘以它本身未尝不可,但是反着来有更简单的实现方法。
对于一个数,它是它倍数的因数,所以我们从(1)到(N)枚举一个数,加上它的所有倍数的和就可以算出答案了。
程序如下:
#include<bits/stdc++.h>
using namespace std;
long long ans;
int n;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j+=i){
ans+=j;
}
}
cout<<ans<<endl;
return 0;
}
E - NEQ
(根据咱的习惯把题目里的(M)、(N)都写成了小写的说)
首先不考虑(B),只考虑(A)。容易看出所有可能的(A)有(m^underline n)种。
然后对于每一种(A),我们考虑有多少种不合法的(B)的情况。
假设有(k)个不合法的位置,那么其余合法的位置有(n-k)个,可以放的数字有(m-k)个,那么其余合法的位置就有((m-k)^underline{n-k})种可能的摆放方法。然后根据容斥原理可以得到如下公式,表示对于每一种(A)有多少个合法的(B):
结合之前对于(A)的可能种数的计算,本题答案如下:
写成对于程序实现友好的形式:
程序如下(但是不比上面的公式好懂):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
inline ll qpow(ll a,ll n){
ll res=1;
while(n){
if(n&1)res=res*a%mod;
a=a*a%mod;
n>>=1;
}
return res;
}
int n,m;
ll ans,f[500005]={1},inv[500005]={1};
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
for(int i=1;i<=5e5;i++){
f[i]=f[i-1]*i%mod;
inv[i]=qpow(f[i],mod-2);
}
cin>>n>>m;
for(int i=0;i<=n;i++){
ans=(ans+f[n]*inv[i]%mod*inv[n-i]%mod*((i&1)?-1:1)*f[m-i]%mod*inv[m-n]%mod)%mod;
}
for(int i=m-n+1;i<=m;i++)ans=ans*i%mod;
cout<<(ans+mod)%mod<<endl;
return 0;
}
F - Unfair Nim
位运算真的太难了qaq
首先在高桥(Takahashi)作弊前,这个题目是一个标准的Nim游戏,对于先手的青木(Aoki)来说,当且仅当(A_1 oplus A_2 oplus dots oplus A_n = 0)时,他一定输掉。否则就是青木的胜利。
那么我们需要通过这一次从第一堆转移到第二堆的操作来使得所有石头堆的异或和为(0),问题就可以转化为如下形式:
给你三个数(A),(B),(C)((A)是(A_1),(B)是(A_2),(C)是(A_3 oplus A_4 oplus dots oplus A_n)),问你是否有两个整数(a),(b),使得(1 leq a leq A)且(a + b = A + B)且(a oplus b = C)。如果有,输出最大的(a),否则输出
-1
。
由于异或就是二进制下不带进位的加法,所以我们可以看出(frac {A + B - C} 2 = A & B)(此处特判(A + B - C)不能被(2)整除的情况)。这样我们定义(D = frac {A + B - C} 2),感性的讲,这就是(A)和(B)两个数中二进制位同为(1)的部分。显然它不能是负数,同时不能比(A)大(毕竟你需要从(A)转移石子到(B),而不是反向转移)。其次,它不能和(C)有共同为(1)的二进制位,因为(a),(b)中的这些位最后异或起来后必定是(0),无法通过操作使得结果为(1)。
然后我们就可以贪心地想了,首先把(D)赋值给(a),然后从高位往低位枚举,假如(C)这一位是(1)同时(a)加上这一位不会比(A)大,那么就可以把(a)的这一位设成(1),最终可以得到最大的可能的(a)(特判最大的(a)是(0)的情况)。
程序非常好写赛时不会的人还有脸说:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
ll A,B,C=0;
cin>>A>>B;
for(int i=3;i<=n;i++){
ll tmp;
cin>>tmp;
C^=tmp;
}
ll D=A+B-C>>1;
if(A+B-C&1||D<0||D>A||D&C){
cout<<"-1
";
return 0;
}
ll a=D;
for(int i=60;i>=0;i--){
if(C>>i&1&&D>>i&1^1&&(a|1ll<<i)<=A){
a|=1ll<<i;
}
}
if(a==0){
cout<<"-1
";
return 0;
}
cout<<A-a<<endl;
return 0;
}