牛客寒假6

 1、进制模拟

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int k;
    std::cin >> k;
    
    std::string s, t;
    std::cin >> s >> t;
    
    std::reverse(s.begin(), s.end());
    std::reverse(t.begin(), t.end());
    
    int n = std::max(s.length(), t.length());
    
    std::vector<int> a(n);
    for (int i = 0; i < int(s.length()); i++) {
        a[i] += s[i] - '0';
    }
    for (int i = 0; i < int(t.length()); i++) {
        a[i] += t[i] - '0';
    }
    
    for (int i = 0; i < n; i++) {
        if (a[i] >= k) {
            if (i == n - 1) {
                a.push_back(0);
                n++;
            }
            a[i + 1]++;
            a[i] -= k;
        }
    }
    
    for (int i = n - 1; i >= 0; i--) {
        std::cout << a[i];
    }
    std::cout << "\n";
    
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
//C = A + B
int k;
vector<int> add(vector<int> &A, vector<int> &B)
{
  vector<int>C;
  int t = 0;//进位
  for(int i = 0; i < A.size() || i < B.size(); i++)
  {
      if(i < A.size()) t += A[i];
      if(i < B.size()) t += B[i];
      C.push_back(t % k);
      t /= k;
  }   
  if(t) C.push_back(1);
  return C;
}
int main()
{
    string a, b;
    scanf("%d",&k);
    vector<int> A, B;
    cin >> a >> b;//a = "123456"
    for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');//A =[6,5,4,3,2,1];
    for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
    auto C = add(A, B);
    //vector<int>C = add(A,B);
    for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
    system("pause");
    return 0;
}
int k, la, lb;
char a[200005], b[200005], c[200005];
int main() {
    cin >> k >> a >> b;
    reverse(a, a + strlen(a));
    reverse(b, b + strlen(b));
    for (int i = 0; a[i] || b[i] || c[i]; i++) {
        if (a[i]) c[i] += a[i] - '0';
        if (b[i]) c[i] += b[i] - '0';
        if (c[i] >= k) c[i] -= k, c[i + 1] += 1;
        c[i] += '0';
    }
    reverse(c, c + strlen(c));
    cout << c << endl;
    return 0;
}

2、+-串模拟 or 规律

纸上写几个例子 注意到 由+ --> - x-=2,由 - ---> + x+=2

真正的模拟

while (T--) {
        scanf("%s", s + 1);
        read(k);
        int n = strlen(s + 1);
        int a = 0, b = 0;
        rep(i, 1, n) {
            if (s[i] == '+')
                ++a;
            else
                ++b;
        }

        这个地方运用了模拟的思想!! 不用推式子!! 直接模拟
        while (k && abs(a - b) > 1) {
            if (a > b)
                --a, ++b;
            else
                ++a, --b;
            --k;
        }


        if(abs(a - b) == 1){cout << "1" <<endl;return 0;}
        if (k) {
            if (k % 2)
                print(2, '\n');
            else
                print(0, '\n');
        } else {
            print(abs(a - b), '\n');
        }
    }
    int balance = 0;
    for (auto c : s) {
        if (c == '+') {
            balance++;
        } else {
            balance--;
        }
    }
     
    balance = std::abs(balance);
     
    int t = std::min(balance / 2, k);
    这一步妙。自行体会。

    balance -= 2 * t;
     (除了特判都符合这个)

    if ((k - t) % 2 == 1 && balance == 0) {
        balance = 2;
    }(特判)
     
    std::cout << balance << "\n";
}

 E、骑士

维护第二大的值max2的时候 首先如果max1被更改,max2一定会改;
然后如果a【i】> mx2 也可以更改mx2 
即mx2的更改有两条途径 
if(a[i]>=mx1){
                mx2=mx1;
                mx1=a[i];id1=i;
            }
            else if(a[i]>=mx2){
                mx2=a[i];
            }

 前缀后缀max

  • 下面这个程序for循环再多只要是并列就是On,下面这个程序是On的
  • 前缀后缀用空间换时间O1查询
pre控制i左边的max1,suf控制i右边的max2
void work() {
    scan(n);
    for(int i = 1; i <= n; ++i) scan(a[i]), scan(b[i]), scan(h[i]);
    pre[0] = 0; for(int i = 1; i <= n; ++i) pre[i] = max(pre[i - 1], a[i]);
    suf[n + 1] = 0; for(int i = n; i >= 1; --i) suf[i] = max(suf[i + 1], a[i]);
    ll ans = 0;
    for(int i = 1; i <= n; ++i) {
        int mx = max(pre[i - 1], suf[i + 1]);   //除了i之外的最大项    
        if(mx >= b[i] + h[i]) ans += mx - b[i] - h[i] + 1;
    }
    print(ans, '\n');
}

D、删除子序列

有点像dp  形成abc的前提是有ab ab的前提是有a a没有前提为inf

int n, m;
char s[M + 5], t[M + 5];
int cnt[30];
 
void work() {
    scan(n), scan(m);
    scanf("%s", s + 1), scanf("%s", t + 1);
    memset(cnt, 0, sizeof cnt);
    cnt[0] = inf;
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            if(s[i] == t[j]) {
                if(cnt[j - 1]) {
                    --cnt[j - 1];
                    ++cnt[j];
                }
            }
        }
    }
    print(cnt[m], '\n');
}

B,价值序列
 

先读懂题目,别把下标和项弄错。

利用数形结合的思想分析问题。先举例从例子入手分析最普遍的情况,然后再想复杂度最高,最特殊的情况。根据这两种情况设计算法。

牛客寒假6

将题目数学化。找规律,归纳,分为集合(划分成不同的部分分别处理)。

相等的数看成联通块。不同的情况不同的贡献用一个if else即可
牛客寒假6


p2[0]=1;
for(int i=1;i<N;i++) p2[i]=p2[i-1]*2%mod;    
for(int i=1;i<=n;i++)
    {
      int j=i;
      while(j<n&&a[j+1]==a[i]) j++;
 
      if(i-1>=1&&j+1<=n&&(a[i-1]<a[i]&&a[j+1]>a[i]||a[i-1]>a[i]&&a[j+1]<a[i]))
        ans=1ll*ans*p2[j-i+1]%mod;
      else ans=1ll*ans*(p2[j-i+1]+mod-1)%mod;
      i=j;
    }

思路无敌清晰 

void solve() {
    int n;
    std::cin >> n;
     
    std::vector<int> a(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }
     
    Z ans = 1;
    std::vector<std::pair<int, int>> b;
    for (int i = 0, j = 0; i < n; i = j) {
        j = i;
        while (j < n && a[i] == a[j]) {
            j++;
        }
        b.emplace_back(a[i], j - i);
    }
     
    for (int i = 0; i < int(b.size()); i++) {
        if (i == 0 || i == int(b.size()) - 1 || (b[i] > b[i - 1]) == (b[i] > b[i + 1])) {
            ans *= power(Z(2), b[i].second) - 1;
        } else {
            ans *= power(Z(2), b[i].second);
        }
    }
     
    std::cout << ans.val() << "\n";
}

void work() {
    scan(n);
    pw[0] = 1;
    for(int i = 1; i <= n; ++i) scan(a[i]), pw[i] = pw[i - 1] * 2 % mod;    
    r[n] = n; for(int i = n - 1; i; --i)  r[i] = (a[i] == a[i + 1] ? r[i + 1] : i);
    int ans = 1;
    for(int i = 1; i <= n; i = r[i] + 1) {
        if(i == 1 || r[i] == n ||
           (a[i - 1] < a[i] && a[r[i]] > a[r[i] + 1]) ||
           (a[i - 1] > a[i] && a[r[i]] < a[r[i] + 1])) {
            ans = (ll)ans * ((pw[r[i] - i + 1] - 1 + mod) % mod) % mod;
        }
        else ans = (ll)ans * pw[r[i] - i + 1] % mod;
    }
    print(ans, '\n');
}
my shabby version :
		l[1] = 1;
		for(int i = 2; i<=n; i++){
			if(ar[i] == ar[i - 1])l[i] = l[i - 1]; if else用三木运算符更牛逼
			else l[i] = i;
		}
		
		for(int i = n; i >= 1; i = l[i] - 1){
			if(i == n || l[i] == 1 ||
				(ar[i] < ar[i + 1] && ar[l[i]] < ar[l[i] - 1] ) ||
				(ar[i] > ar[i + 1] && ar[l[i]] > ar[l[i] - 1] ))
				ans = (ll)ans * ((pw[i - l[i] + 1] - 1 + mod)%mod)%mod; 
		else{
			//(ans *= pw[i - l[i] + 1]%mod)%mod;
            必须先乘再%
               ans = ans * pw[i - l[i] + 1] % mod
		} 
	}

上一篇:CCF-CSP认证 202112-3 登机牌条码(90分)


下一篇:django<一安装和创建项目>