A-Sliding
思路
可能翻译出来题意比较无语,实际上就是一个n*m的表格,第r,c走了,剩下的在他后面的点移动道他们前面的那个点的位置,问移动的麦哈顿距离,我们画图就能够发现第r+1到第n行的第一个会移动m搁,其他就是一格
代码
void solve() {
ll n, m, r, c;
cin >> n >> m >> r >> c;
ll ans = 0;
ans = ans + (n - r) * m;
ll ans2 = 0;
ans2 = ans2 + (n - r) * (m - 1) + (m - c);
cout << ans + ans2;
}
B-Everyone Loves Tres
思路
打表就行,由于找最小的被33和66整除的,我们打表就会发现,除了1,3没有答案外,
奇数为n6366
偶数维n66
代码
void solve() {
/*ll x = 66;打表
for (int i = 1; i <= 10000000000; i++) {
ll y = i * x;
ll mark = 1;
while (y > 0) {
ll a = y % 10;
if (a != 6 && a != 3) {
mark = 0;
}
y = y / 10;
}
if (mark) {
cout << i*x << endl;
}
}*/
ll n;
cin >> n;
if (n == 1 || n == 3) {
cout << "-1";
return;
}
if (n % 2 == 0) {
for (int i = 1; i <= n - 2; i++) {
cout << "3";
}
cout << "66";
}
else {
for (int i = 1; i <= n - 4; i++) {
cout << "3";
}
cout << "6366";
}
}
C-Alya and Permutation
思路
尽管有人说是打表题,但实际上可以证明,我们先令X为一个01字符串,
奇数:最后一位一定是X1,那么上一位一定是X0,由于奇数位是并操作,所以最后的答案最大就是是n,那么对于X0取或之后再对X1取并会发现少了个一,解决发放就是在n-2和n-3上面放两个奇数就可以了
偶数:最后一位应该是1X0,我们已经知道n为奇数时能创建除了,那么我们就在n-1位上去实现X0,然后最后一位取或就能够实现111111的结果了
代码
void solve() {
ll n;
cin >> n;
ll k = 0;
if (n & 1) {
cout << n << endl;
for (int i = 2; i <= n - 3; i++) {
cout << i << " ";
}
cout << "1" << " " << n - 2 << " " << n - 1 << " " << n;
}
else {
int ans = 0;
for (int i = 0; i <= 100; i++) {
ll b = ((ll)1 << i);
if (b > n) {
ans = b - 1;
break;
}
}
cout << ans << endl;
ll sum1 = 0;
for (int i = 0; powl(2, i) <= n; i++) {
ll x = ((ll)1 << i);
if ((x & n) == 0) {
sum1 = sum1 | x;
}
}
if (sum1 <= 3) {
n--;
for (int i = 2; i <= n - 3; i++) {
cout << i << " ";
}
cout << "1" << " " << n - 2 << " " << n - 1 << " " << n << " " << n + 1 ;
}
else {
map<ll, ll>brr;
for (int i = 2; i <= sum1 - 3; i++) {
brr[i]++;
}
brr[1]++;
brr[sum1 - 2]++;
brr[sum1 - 1]++;
brr[sum1]++;
for (int i = 1; i <= n - 1; i++) {
if (brr[i] == 0) {
cout << i << " ";
}
}
for (int i = 2; i <= sum1 - 3; i++) {
cout << i << " ";
}
cout << "1" << " " << sum1 - 2 << " " << sum1 - 1 << " " << sum1 << " " << n;
}
}
}
D-Yet Another Real Number 问题
思路
算是一道模拟题吧,我们先把数字分解成不能被2整除的形式,拿样例说一遍
1 2 3 4 5 6 7 8 9 10
1 1 3 1 5 3 7 1 9 5 分解成的奇数
0 1 0 2 0 1 0 3 0 1 分解成的2的数量
那么我们从前往后走,我们发现到了一个位置,会出现一个状态,是应该让前面的一个数字去乘以他前面的2的数量还是让全部的2去乘以最后的2的数量,这个情况其实很好解决,我们到达一个位置,如果前面那个数字到达当前的数字所有的2依旧小于前面的那个数字,那就不用选当前的位置,否者,就选最后的这个位置就可以了,
用优先队列维护即可
代码
struct node {
ll id = 0;
ll sum2 = 0;
ll x = 0;
node() {};
node(ll a, ll b, ll c) {
id = a;
x = b;
sum2 = c;
}
};
bool operator <(node a, node b) {
return a.id < b.id;
}
priority_queue<node>dp;
void solve() {
ll n;
cin >> n;
while (dp.size()) {
dp.pop();
}
vector<vector<ll>>arr(n + 2, vector<ll>(4));
for (int i = 1; i <= n; i++) {
cin >> arr[i][1];//1存数字;
ll y = arr[i][1];
ll k = 0;
while (y % 2 == 0) {
k++;
y = y / 2;
}
arr[i][1] = y;
arr[i][2] = k;
}
/* for (int i = 1; i <= n; i++) {
cout << arr[i][1] << " " << arr[i][2] << endl;
}*/
ll ans = 0;
for (int i = 1; i <= n; i++) {
//debug;
//cout << i << endl;
ans = ans % mod;
while (dp.size()) {
node now = dp.top();
//cout << now.id << " " << now.x << " " << now.sum2 << endl;
if (arr[i][1]*ksm(2,arr[i][2])>=now.x) {
if (now.sum2 == 0) {
dp.pop();
continue;
}
arr[i][2] += now.sum2;
ans = ans + mod - now.x*ksm(2, now.sum2) % mod;
ans = ans + now.x;
ans = ans % mod;
ans = ans % mod;
dp.pop();
}
else {
break;
}
}
node now = node(i, arr[i][1], arr[i][2]);
dp.push(now);
//cout << ans << " " << i << endl;
ans = ans + arr[i][1] * ksm(2, arr[i][2]) % mod;
ans = ans % mod;
//cout << "ans="<<ans << " " << endl;
cout << ans << " ";
}
}