比赛传送门
看到unrated直接睡觉去了(手动狗头) ,又错失一次 上分 掉分好时机QAQ。
A. Odd Divisor
题意:
判断整数n有没有奇数因子(odd divisor)。
思路:
签到题
Code:
int main() {
int t;
cin >> t;
while (t--) {
LL n;
cin >> n;
while (n % 2 == 0) {
n /= 2;
}
if (n == 1) cout << "NO" << endl;
else cout << "YES" << endl;
}
return 0;
}
B. New Year’s Number
题意:
判断整数n是否可以写出x*2020+y*2021的形式。
思路:
看n除以2020的余数 乘以2021会不会超过n。若超过n则不可以,反之则可以。
Code:
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
if ((n%2020)*2021 <= n) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
C. Ball in Berland
题意:
一个男生和一个女生配成一对,总共有k对,求选两对男女同台演出的方案数。
思路:
假设有两对,分别为(x1,y1),(x2,y2)。那么要保证x1 != x2 && y1 != y2。
首先不考虑能不能同台表演,总的方案数应该是C(k,2)。
比如说这里的男1,他可以分别和女234配对,但很明显所组成的三个对每次选择只能在三个中选一个,也就是说对于答案而言,损失了2+1=3个方案,。女2,女4同理。
所以,最终的答案应该是C(k,2)- Σq。其中q为 0+···+(a[i]-1)。
Code:
int a[200005], b[200005];
map<int, int> A;
map<int, int> B;
ll sum(int n) {
return 1ll*(1+n)*n/2;
}
int main() {
int t;
read(t);
while (t--) {
int n, m, k;
read(n), read(m), read(k);
A.clear(), B.clear();
for (int i = 0; i < k; i++) {
read(a[i]);
A[a[i]]++;
}
for (int i = 0; i < k; i++) {
read(b[i]);
B[b[i]]++;
}
ll ans = k*1ll*(k-1)/2;
for (int i = 0; i < k; i++) {
if (A[a[i]]>1) ans -= sum(A[a[i]]-1), A[a[i]] = 0;
if (B[b[i]]>1) ans -= sum(B[b[i]]-1), B[b[i]] = 0;
}
cout << ans << endl;
}
}
D. Cleaning the Phone
题意:
手机有n个应用程序,第i个应用占ai个单位的内存,便利点(convenience points)为bi。现在要清理出至少m个单位的内存空间,要求损失最少的便利点。
思路:
便利点只有1和2,首先把便利点为1的和2的分开来存,按递减排序,然后枚举便利点为 1的数组,取其前i个数,对于每种情况,在便利点为2的前缀和中二分找剩余内存的对应的下标,1i+2pos即为该情况下的最优解,最后取最小值更新答案。
Code:
int main() {
int t;
cin >> t;
while (t--) {
int n, m, ia = 1, ib = 1;
LL sum = 0;
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> tmp[i];
sum += tmp[i];
}
for (int i = 0; i < n; i++) {
LL x;
cin >> x;
if (x == 1) a[ia++] = tmp[i];
else b[ib++] = tmp[i];
}
if (sum < m) {
cout << -1 << endl;
continue;
}
sort(a+1, a+ia, cmp);
sort(b+1, b+ib, cmp);
for (int i = 1; i < ib; i++) {
sumb[i] = sumb[i-1] + b[i];
}
LL ans = INF, cnt = 0;
for (int i = 0; i < ia; i++) {
cnt += a[i];
if (cnt >= m) {
ans = min(ans, 1LL*i);
break;
}
int dt = m - cnt;
int pos = lower_bound(sumb+1, sumb+ib, dt) - sumb;
if (pos == ib) continue;
ans = min(ans, 1LL*i+2*pos);
}
int pos = lower_bound(sumb+1, sumb+ib, m) - sumb;
if (pos != ib)
ans = min(ans, 2LL*pos);
cout << ans << endl;
}
return 0;
}
E. Advertising Agency
题意:
总共有n个人,第i个人对应权值ai。在n个人中雇k个,使得权值最大,求方案数。
思路:
假设8个人中选5个,出现这种情况:
4 3 3 2 2 2 2 1
理解题意可知,以上例子中,重复的3不需要考虑,而重复的2恰好位于选与不选之间,所以就会有多种方案(事实上4 3 3 2 2存在6种情况)。j设a为2的总数,b为需要选2的个数,很容易推出,其实答案是C(a,b),对答案取模1e9+7。可以用拓展欧几里得,边求组合数边取模。
Code:
const int mod = 1e9+7;
int a[1005];
int cmp(int a, int b) {
return a > b;
}
const int maxn = 1005;
LL fac[maxn];
LL ex_gcd(LL a,LL b,LL &x,LL &y){
if(b==0){x = 1;y = 0;return a;}
LL ans = ex_gcd(b,a%b,x,y);
LL temp = x;
x = y;
y = temp - (a/b)*y;
return ans;
}
LL inv(LL a){
LL x,y;
int ans = ex_gcd(a,mod,x,y);
if(ans!=1)return -1;
if(x<0)x = (x%mod+mod)%mod;
return x;
}
void solve(){
fac[0] = 1;
for(int i = 1;i<=maxn-1;i++){
fac[i] = (fac[i-1]*i)%mod;
}
}
LL comb(int n,int k){
if(k>n)return 0;
return (fac[n]*inv(fac[k])%mod*inv(fac[n-k])%mod)%mod;
}
int main() {
int t;
solve();
read(t);
while (t--) {
int n, k;
read(n), read(k);
for (int i = 1; i <= n; i++) read(a[i]);
sort(a+1, a+1+n, cmp);
int sum = 0, pos = -1;
for (int i = 1; i <= n; i++) {
if (pos == -1 && a[i] == a[k]) pos = i;
if (a[i] == a[k]) sum++;
if (a[i]<a[k]) break;
}
int sel = k-pos+1;
cout << comb(sum, sel) << endl;
}
return 0;
}
F. Unusual Matrix
题意:
给你一个初始二进制矩阵,问你经过操作:
1.对行异或;
2.对列异或能不能转换成目标矩阵。
思路:
先预处理:找出初始矩阵与目标矩阵有差异的地方,一样的地方用0表示,不一样的用1表示。有差异那就说明:这个点一定是要经过转换的,而转换偶数次是没有意义的,只能转换奇数次。
对于点(x,y)来说,如果要转换它,就意味着要连带转换(1,y)或(x,1)这个点,而(1,y)、(x,1)又可以通过改变(1,1)变回来,所以,如果这四个点全相同或者有两个不同,就可以完成转换,反之,则不可。
Code:
string s;
int mp[1005][1005];
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> s;
for (int j = 0; j < n; j++)
mp[i][j+1] = s[j]-'0';
}
for (int i = 1; i <= n; i++) {
cin >> s;
for (int j = 0; j < n; j++)
mp[i][j+1] ^= s[j]-'0';
}
int flag = 0;
for (int i = 2; i <= n; i++) {
for (int j = 2; j <= n; j++) {
if (mp[1][j]^mp[i][1]^mp[1][1]^mp[i][j]) {
flag = 1;
break;
}
}
}
if (flag) puts("NO");
else puts("YES");
}
return 0;
}