A. Spy Detected!
题解:输出只出现一次的数。
#include<bits/stdc++.h>
using namespace std;
int a[110], mp[110];
int main()
{
int t, n, i;scanf("%d", &t);
while (t--){
memset(mp, 0, sizeof(mp));
scanf("%d", &n);
for (i = 1; i <= n; i++){
scanf("%d", &a[i]);
mp[a[i]]++;
}
for (i = 1; i <= n; i++){
if (mp[a[i]] == 1){
printf("%d\n", i);
break;
}
}
}
}
B. Almost Rectangle
题意:输出由四个‘ * ’组成的矩形。
题解:构造。已知的两个‘ * ’和未知的两个‘*'同行或同列或同一对角线。
#include<bits/stdc++.h>
using namespace std;
char mp[410][410];
int main()
{
int t, n, i, j;scanf("%d", &t);
while (t--){
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%s", mp[i]);
int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++){
if (mp[i][j] == '*'){
if (x1 == -1 && y1 == -1) x1 = i, y1 = j;
else if (x2 == -1 && y2 == -1) x2 = i, y2 = j;
}
}
if (x1 == x2){//同行
if (x1 == 0) mp[x1 + 1][y1] = mp[x2 + 1][y2] = '*';
else mp[x1 - 1][y1] = mp[x2 - 1][y2] = '*';
}
else if (y1 == y2){//同列
if (y1 == 0) mp[x1][y1 + 1] = mp[x2][y2 + 1] = '*';
else mp[x1][y1 - 1] = mp[x2][y2 - 1] = '*';
}
else{//对角线
mp[x1][y2] = mp[x2][y1] = '*';
}
for (i = 0; i < n; i++)
printf("%s\n", mp[i]);
}
}
C. A-B Palindrome
题意:将原字符串构造成由a个0和b个1组成的字符串。
题解:构造。首先考虑-1的情况:
1.ab都为奇数,一定有一位多出来。
2.原字符串不是回文串。
3.原字符串中01个数比ab多。
然后根据已有01补齐对应问号,再根据ab补齐剩余问号。
#include<bits/stdc++.h>
using namespace std;
char s[400010];
int main()
{
int t, a, b, i;scanf("%d", &t);
while (t--){
scanf("%d%d%s", &a, &b, s);
if (a % 2 && b % 2){//ab都为奇数
printf("-1\n");
continue;
}
int flag = 1, l = strlen(s);
for (i = 0; i < l / 2; i++){//判断原字符串是否回文
if (s[i] == '?' || s[l - i - 1] == '?') continue;//一位有'?'不需要判断
if (s[i] != s[l - i - 1]) flag = 0;
}
if (!flag){
printf("-1\n");
continue;
}
int cnt0 = 0, cnt1 = 0;
for (i = 0; i < l; i++){
if (s[i] == '0') cnt0++;
else if (s[i] == '1') cnt1++;
}
if (cnt0 > a || cnt1 > b){//判断字符串中01个数是否合法
printf("-1\n");
continue;
}
a -= cnt0, b -= cnt1;
bool boo = 1;
for (i = 0; i < l; i++){//根据已有01去单个问号
if (s[i] == '0' && s[l - i - 1] == '?'){
if (a) a--, s[l - i - 1] = '0';
else{
boo = 0;
break;
}
}
else if (s[i] == '1' && s[l - i - 1] == '?'){
if (b) b--, s[l - i - 1] = '1';
else{
boo = 0;
break;
}
}
}
if (!boo){
printf("-1\n");
continue;
}
for (i = 0; i < l; i++){//根据ab补齐剩余问号
if (s[i] == '?'){
if (i == l / 2){//补一位
if (a) a--, s[i] = '0';
else if (b) b--, s[i] = '1';
else{
boo = 0;
break;
}
continue;
}
//补两位
if (a >= 2){
s[i] = s[l - i - 1] = '0';
a -= 2;
}
else if (b >= 2){
s[i] = s[l - i - 1] = '1';
b -= 2;
}
else{
boo = 0;
break;
}
}
}
if (!boo) printf("-1\n");
else printf("%s\n", s);
}
}
D. Corrupted Array
题意:给一个b数组,前n项和a数组中的每一项相同,第n+1项等于a数组前n项和,第n+2项等于x。求a数组。
题解:假设b数组升序,分两种情况。
1.第n+1项次大,x最大,判断b数组前n项和与b[n+1]是否相同。
2.第n+1项最大,x次大,在前n+1项中枚举x,判断b数组的前n+1项和 减x的值与b[n+2]是否相同。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int b[200010];
int main()
{
int t, n, i;scanf("%d", &t);
while (t--){
scanf("%d", &n);
for (i = 1; i <= n + 2; i++)
scanf("%d", &b[i]);
sort(b + 1, b + n + 3);
ll sum = 0;
for (i = 1; i <= n; i++)
sum += b[i];
if (sum == b[n + 1]){//第一种情况
for (i = 1; i <= n; i++){
if (i > 1) printf(" ");
printf("%d", b[i]);
}
printf("\n");
}
else{
sum += b[n + 1];//第二种情况
int x = -1;
for (i = 1; i <= n + 1; i++){
if (sum - b[i] == b[n + 2]){
x = b[i];
break;
}
}
if (x != -1){
int p = 0, ok = 0;
for (i = 1; i <= n + 1; i++){
if (!ok && b[i] == x){//等于x的那一项不能输出
ok = 1;
continue;
}
if (p) printf(" ");
printf("%d", b[i]);
p++;
}
printf("\n");
}
else printf("-1\n");
}
}
}
E. Permutation by Sum
题意:判断[l,r]的和与s是否相等。
题解:从最小的区间[1,2,…,r-l+1]开始,从后往前一位一位的增加,每位最多增加n-(r-l+1)。
#include<bits/stdc++.h>
using namespace std;
int a[510], vis[510];//标记值
int main()
{
int t;scanf("%d", &t);
while (t--){
int n, l, r, s;
scanf("%d%d%d%d", &n, &l, &r, &s);
int minn = (1 + r - l + 1) * (r - l + 1) / 2;//最小序列和
if (minn > s) printf("-1\n");
else{
memset(vis, 0, sizeof(vis));
memset(a, 0, sizeof(a));
s -= minn;
for (int i = l; i <= r; i++)
a[i] = i - l + 1;
for (int i = r; i >= l; i--){
int add = n - (r - l + 1);//每个数能加的最大值
if (s >= add){
a[i] += add, s -= add;
vis[a[i]] = 1;
}
else{
a[i] += s, s = 0;
vis[a[i]] = 1;
}
}
if (s > 0){//s不能恰好分配完
printf("-1\n");
continue;
}
for (int i = 1; i <= n; i++){//位置
if (!a[i]){
for (int j = 1; j <= n; j++){//区间外的数
if (!vis[j]){
a[i] = j;
vis[j] = 1;
break;
}
}
}
if (i > 1) printf(" ");
printf("%d", a[i]);
}
printf("\n");
}
}
}
F. Education
题意:现有n个长度的a数组和n-1个长度的b数组,c为购买电脑的费用。ai表示每天获得的钱,bi表示晋升到ai+1需要花费的钱。问最少几天能买得起电脑。
题解:思维、枚举。如果钱足够,能晋升的话就选择晋升,因为能获得更多的钱。再枚举ai,比较购买电脑的天数和晋升的天数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[200010], b[200010];
int main()
{
int t;scanf("%d", &t);
while (t--){
int n, c;scanf("%d%d", &n, &c);
for (int i = 0; i < n; i++)
scanf("%lld", &a[i]);
for (int i = 0; i < n - 1; i++)
scanf("%lld", &b[i]);
ll minn = 1e18 + 10;
ll newdays = 0, cur = 0, money = 0;//晋升天数,当前天数,当前的钱
for (int i = 0; i < n; i++){
minn = min(minn, cur + (c - money + a[i] - 1) / a[i]);//以当前薪资水平购买电脑的最少天数
newdays = (b[i] - money + a[i] - 1) / a[i];
cur += newdays + 1;//晋升还需要单独的一天
money += newdays * a[i] - b[i];//晋升后剩余的钱
}
printf("%lld\n", minn);
}
}
G. Short Task
题解:思维。dn=1 + n +… = c, 故n<c,n的范围在[1,1e7]。先按照埃氏筛的方式求出di,再记录di对应的最小的数,最后找到c对应的位置。
#include<bits/stdc++.h>
using namespace std;
int d[10000010], pos[10000010];
void init()
{
for (int i = 1; i <= 1e7; i++)
for (int j = i; j <= 1e7; j += i)
d[j] += i;//数j的因子之和
for (int i = 1; i <= 1e7; i++){
if (d[i] <= 1e7)
if (!pos[d[i]]) pos[d[i]] = i;//pos记录di的最小位置
}
}
int main()
{
init();
int t;scanf("%d", &t);
while (t--){
int n;scanf("%d", &n);
if (!pos[n]) printf("-1\n");
else printf("%d\n", pos[n]);
}
}