A.Permutation
思路:这题比较水,计数算出1-n中重复的数的个数就是最少的改变次数
#include
#include
const int maxn = 5000+10;
bool has[maxn];
int n, ans, tmp;
int main()
{
while(scanf("%d", &n) != EOF)
{
ans = 0;
memset(has, false, sizeof(has));
for(int i = 0; i < n; i++)
{
scanf("%d", &tmp);
if(tmp < 1 || tmp > n)
ans++;
else if(has[tmp])//重复的数用来修改
ans++;
else
has[tmp] = true;
}
printf("%d\n", ans);
}
return 0;
}
公约数存在arr[]数组中,这样每个询问相当于在arr[]中找到一个最大的数使他在询问要求的区间中。可以把arr[]排序后二分查找这个数。
#include
#include
#include
using namespace std;
const int maxn = 40000+10;
int a, b, n, gcd, low, hig;
int arr[maxn*2], cnt;
int Gcd(int a, int b)
{
if(b == 0)
return a;
return Gcd(b, a % b);
}
void GetYue(int tar)//求最大公约数的所有约数
{
// int up = floor(sqrt((double)tar));
// cnt = 0;
// if(tar % up == 0)
// arr[cnt++] = up;
// for(int i = 1; i < up; i++)
// if(tar % i == 0)
// arr[cnt++] = i, arr[cnt++] = tar / i;
for(int i = 1; i*i <= tar; i ++){
if(tar%i==0){
arr[cnt++] = i;
if(tar/i!=i) arr[cnt++] = tar/i;
}
}
sort(arr, arr+cnt);
}
int Query(int lo, int hi)
{
// int p = upper_bound(arr, arr+cnt, hi) - arr - 1;
// return arr[p] >= lo ? arr[p] : -1;
int l = 0, r = cnt-1;
while(l < r)
{
int mid = r-(r-l)/2;
if(arr[mid] < lo)
l = mid+1;
else if(arr[mid] > hi)
r = mid-1;
else
l = mid;
}
if(l > r || arr[l] < lo || arr[l] > hi)
return -1;
else
return arr[l];
}
int main()
{
while(scanf("%d%d", &a, &b) != EOF)
{
scanf("%d", &n);
gcd = Gcd(a, b);
GetYue(gcd);
for(int i = 0; i < n; i++)
{
scanf("%d%d", &low, &hig);
printf("%d\n", Query(low, hig));
}
}
return 0;
}
C.Fancy Number
数字只有0-9十个,所以我们可以枚举最后相同的数, 然后选出最优解
我们以最后达到10个5为目标,现在又2个5,则要把8个其他数字改为5,这题以花费最少、其次字典序最小为目标,所以遵循几个原则:
1.首先我们改变的数字和目标数字(5)的绝对值要最小(最小花费)
2.当两个数绝对值相同时,先把比目标数字大的数改为目标数字(这样字典序变小了)
3.当两个数相同时,如果这个数比目标数字大,先改变高位那个(字典序变小的多);如果这个数比目标数小则改变地位那个(字典序变大的少)
4.对求出来的十个答案进行比较(花费和字典序)
#include
#include
const int maxn = 10000+10;
int len, k;
char str[maxn], ans[10][maxn];
int cnt[maxn], cost[10];
int chn[10];//改变dif[i]个差值为i的数
bool OK()
{
for(int i = 0; i < 10; i++)
if(cnt[i] >= k)
return true;
return false;
}
void ChangeTo(int tar)
{
int res = k - cnt[tar], dif = 1;
memset(chn, 0, sizeof(chn));
while(true)
{
if(res <= 0)
break;
if(tar+dif < 10)
{
if(cnt[tar+dif] >= res)
chn[tar+dif] = res, res = 0;
else
chn[tar+dif] = cnt[tar+dif], res -= cnt[tar+dif];
}
if(res <= 0)
break;
if(tar-dif >= 0)
{
if(cnt[tar-dif] >= res)
chn[tar-dif] = res, res = 0;
else
chn[tar-dif] = cnt[tar-dif], res -= cnt[tar-dif];;
}
dif++;
}
cost[tar] = 0;
for(int i = 0; i < 10; i++)
if(chn[i])
cost[tar] += chn[i] * (tar > i ? tar - i : i - tar);
for(int i = 0; i < len; i++)
{
ans[tar][i] = str[i];
int num = str[i] - '0';
if(num > tar && chn[num])//改变小的
ans[tar][i] = tar + '0', chn[num]--;
}
for(int i = len-1; i >= 0; i--)
{
int num = str[i]-'0';
if(num < tar && chn[num])
ans[tar][i] = tar + '0', chn[num]--;
}
ans[tar][len] = 0;
}
bool Cmp(int id1, int id2)
{
if(cost[id1] < cost[id2])
return true;
else if(cost[id1] > cost[id2])
return false;
for(int i = 0; i < len; i++)
{
if(ans[id1][i] < ans[id2][i])
return true;
else if(ans[id1][i] > ans[id2][i])
return false;
}
return false;
}
int main()
{
while(scanf("%d%d", &len, &k) != EOF)
{
scanf("%s", str);
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < len; i++)
cnt[str[i]-'0']++;
if(OK())
{
printf("%d\n%s\n", 0, str);
continue;
}
for(int i = 0; i < 10; i++)//枚举相同的数
ChangeTo(i);
int ansId = 0;
for(int i = 1; i < 10; i++)
{
if(Cmp(i, ansId))//答案i更优
ansId = i;
}
printf("%d\n%s\n", cost[ansId], ans[ansId]);
}
return 0;
}
#include
const int maxn = 100+10;
struct Rob{
int x, y, dir;
};
Rob rob[maxn];
int dx[] = {1, 0, -1, 0};//ESWN东南西北
int dy[] = {0, -1, 0, 1};
int matrix[maxn][maxn], A, B;
int tcase, N, M;
int DIR(char cc)
{
if(cc == 'E') return 0;
else if(cc == 'S') return 1;
else if(cc == 'W') return 2;
else return 3;
}
bool GoNext(int id, char cmd, int cnt)
{
if(cmd == 'L')
{
rob[id].dir = (rob[id].dir-cnt+100)%4;
return false;//没有失败
}
else if(cmd == 'R')
{
rob[id].dir = (rob[id].dir+cnt)%4;
return false;
}
else
{
int nowx = rob[id].x, nowy = rob[id].y, dd = rob[id].dir;
for(int i = 0; i < cnt; i++)
{
int ntx = nowx + dx[dd], nty = nowy + dy[dd];
if(ntx < 1 || ntx > A || nty < 1 || nty > B)//撞墙
{
printf("Robot %d crashes into the wall\n", id);
return true;//失败了
}
else if(matrix[ntx][nty] != 0)//撞机器
{
printf("Robot %d crashes into robot %d\n", id, matrix[ntx][nty]);
return true;
}
else
nowx = ntx, nowy = nty;//可以走
}
matrix[nowx][nowy] = id;
matrix[rob[id].x][rob[id].y] = 0;
rob[id].x = nowx, rob[id].y = nowy;
return false;
}
}
int main()
{
char cmd[5];
int id, cnt;
scanf("%d", &tcase);
while(tcase--)
{
scanf("%d%d%d%d", &A, &B, &N, &M);
for(int i = 1; i <= A; i++)
for(int j = 1; j <= B; j++)
matrix[i][j] = 0;
for(int i = 1; i <= N; i++)
{
scanf("%d%d%s", &rob[i].x, &rob[i].y, cmd);
rob[i].dir = DIR(cmd[0]);
matrix[rob[i].x][rob[i].y] = i;
}
bool fail = false;//前面的操作是否已经失败了
for(int i = 1; i <= M; i++)
{
scanf("%d%s%d", &id, cmd, &cnt);
if(fail)
continue;
fail = GoNext(id, cmd[0], cnt);
}
if(!fail)
printf("OK\n");
}
return 0;
}
#include
const int maxn = 20+10;
char str[maxn*2];
int n, tcase;
int main()
{
scanf("%d", &tcase);
while(tcase--)
{
scanf("%d", &n);
int has = 0, len = 0, num;//has已有的'('个数
for(int i = 0; i < n; i++)
{
scanf("%d", &num);
for(; has < num; has++)
str[len++] = '(';
str[len++] = ')';
}
//先还原字符串
bool first = true;
for(int i = 0; i < len; i++)
{
if(str[i] == ')')
{
int cnt = 1, j;
for(j = i-1; str[j] != '('; j--)
if(str[j] == 'R')
cnt++;
str[j] = 'L', str[i] = 'R';//已匹配的括号做标记
if(!first)
putchar(' ');
first = false;
printf("%d", cnt);
}
}
puts("");
}
return 0;
}
F.Not a Triangle
2000条线段,直接枚举三条边肯定爆。
这样我们就排序后枚举三角形中小的两条边a, b为num[x1], num[x2],
然后第三条边(最大的边)肯定在num[x2+1]~num[n-1]中,二分查找可以做第三条边的边数,N*N*ln(N)
#include
#include
#include
using namespace std;
const int maxn = 2000+10;
int len[maxn], n;
int Find(int l, int r, int tt)//在[l, r]寻找>tt的个数
{
if(l > r)
return 0;
int up = upper_bound(&len[l], &len[r]+1, tt)-&len[l];
if(len[l+up] == INT_MAX)
return 0;
else
return (r-l+1)-up;
}
int main()
{
while(scanf("%d", &n) != EOF && n)
{
for(int i = 0; i < n; i++)
scanf("%d", &len[i]);
sort(len, len+n);
int ans = 0;
len[n] = INT_MAX;
for(int i = 0; i < n; i++)
for(int j = i+1; j < n; j++)
ans+=Find(j+1, n-1, len[i]+len[j]);
printf("%d\n", ans);
}
return 0;
}