第二次比赛部分题题解

C. Sasha and a Bit of Relax

关于异或运算,你需要挖掘它的性质,否则这个题找不到规律是没办法做出来的。

$a_l\oplus a_{l+1} \cdots \oplus a_{mid} = a_{mid+1}\oplus \cdots \oplus a_r $

则可以推出\(a_l\oplus a_{l+1} \cdots \oplus a_{mid} \oplus a_{mid+1}\oplus \cdots \oplus a_r = 0\)

又因为对于任意一个正整数 x 都有\(x \oplus 0 = x\) 。所以这个题就可以冒险试一试了。

#include <bits/stdc++.h>
using namespace std;
int n;
long long has[(1<<20)+10][2];//has[x][0]表示x在偶数位出现的次数
int main(){
    cin>>n;
    long long num = 0,pre=0;
    for(int i=1,x;i<=n;i++){
        scanf("%d",&x);
        has[pre][(i-1)%2]++;
        pre ^= x;
        num += has[pre][i%2];
    }
    cout<<num<<endl;
    return 0;
}

但是可以稍微证明一下,为什么一段数字的异或为0,然后它们对半分就一定相等呢?

因为如果异或为0,那么这一段数字二进制表示上,每一位上面的1的个数和都为偶数个,那么我们把这段数字对半分后,这些偶数个1的拆分只能有两种情况,都为偶数,都为奇数。可见分开后的二进制位上的1的个数的奇偶性相同,即异或的结果是相同的。

D. Sasha and One More Name

首先可以想到的是,如果字符串中所有的字符都相同,或者只有一个不同,那么这个回文串是无法重构成与原串不同的回文串的。

然后我们分情况讨论:

  • 长度为奇数时,我们总可以找个一对对称的位置,调换之后可以构成一个不同的回文串(满足上述条件,即存在不同的多个字符)
  • 长度为偶数时,假设从中间分开之后反过来重新拼接得到t,如果前半段不是一个回文串,那么t和原串s是不同的。但是如果前半段是一个回文串呢?这意味这什么?这说明前半段和后半段是相同的,也就是说出现了循环节。由于s长度最多为5000,所以只需要从尾到头,每次只把一小部分字符挪到前面,判断是否为回文串并且不等于原串即可判断是否存在只需一刀的解。
#include <bits/stdc++.h>
using namespace std;

bool isPalindrome(const string& s) {
    for(int i = 0; i < s.length(); ++i) {
        if (s[i] != s[s.length() - i - 1]) 
            return false;
    }
    return true;
}

bool solve1(string s) {
    string t = s;
    int len = s.length();
    for(int i = 0; i < len; ++i) {
        t = t[len-1] + t;//每次拼接一部分,从尾部拿到头部
        t.resize(len);//重新调整大小
        if (s != t && isPalindrome(t)) {
            return true;
        }
    }
    return false;
}
//判断是否存在多个不同字符
bool anyAnswer(const string& s) {
    int nt = 0;
    for(int i = 0; i < s.length(); ++i) {
        nt += s[i] != s[0];
    }
    return nt > 1;
}

int main() {
    string s;
    cin >> s;
    if (anyAnswer(s)) {
        cout << (solve1(s) ? 1 : 2) << endl;
    } else {
        cout << "Impossible" << endl;
    }
    return 0;
}

结合着CF题解看吧,鄙人能力有限

https://codeforces.com/blog/entry/65295

G - Magic Ship

  • 首先坐标范围1e9,再加上风的影响,可以知道答案会非常大,如果推公式的话,因为有风的影响发现公式很难确定。所以可以尝试二分答案。
  • m为天数,可以提前将风的影响通过前缀算出来。然后其加到坐标上,只需判断该坐标与终点的曼哈顿距离是否小于等于m即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll X1,Y1,X2,Y2,n;
char s[100010];
ll prex[100010],prey[100010];
bool check(ll m){
    ll dx = m/n*prex[n]+prex[m%n] + X1;
    ll dy = m/n*prey[n]+prey[m%n] + Y1;
    return abs(X2-dx)+abs(Y2-dy)<=m;
}
int main(){
    cin>>X1>>Y1>>X2>>Y2>>n;
    scanf("%s",s+1);
    for(int i=1;i<=n;i++){
        prex[i] = prex[i-1];
        prey[i] = prey[i-1];
        if(s[i]=='U') prey[i]++;
        else if(s[i]=='D') prey[i]--;
        else if(s[i]=='R') prex[i]++;
        else if(s[i]=='L') prex[i]--;
    }
    ll l = 0,r = 1e18;
    int flag = 0;
    while(l<r){
        ll mid = (l+r)/2;
        if(check(mid)){
            r = mid;
            flag = 1;
        }
        else l = mid+1;
    }
    if(flag)
    cout<<r<<endl;
    else cout<<-1<<endl;
}
posted @ 2019-02-21 11:19  长安大学ACM  阅读(172)  评论(0编辑  收藏  举报