UNIQUE VISION Programming Contest 2022 Winter(AtCoder Beginner Contest 283)

A - Power

Given integers A and B, print the value A^B.

基础不解答

B - First Query Problem

基础不解答

C - Cash Register

Takahashi is a cashier.
There is a cash register with 11 keys: 00, 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. The cash register initially displays 00. Whenever he types the key 00, the displayed number is multiplied by 100; whenever he types one of the others, the displayed number is multiplied by 10, and then added by the number written on the key.
Takahashi wants the cash register to display an integer S. At least how many keystrokes are required to make it display S?

Solution

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int a[100005];
int main(){
	string s;
	cin>>s;
	int len = s.length();
	int ans = len;
	int t = 0;
	for(int i = 0; i < len;){
		if(s[i] == '0'){
			int j;
			for(j = i+1;j < len;j++){
				if(s[j] != '0'){
					break;
				}
			}
			if(j - i > 1){
				t = j - i;
				t = t/2;
				ans = ans - t;
			}
			i = j;
		}
		else{
			i++;
		}
	}
	printf("%d\n",ans);
	return 0;
}

D - Scope

D - Scope (atcoder.jp)

Solution

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int b[100005];
int main(){
	string str;
	cin>>str;
	stack<char> st;
	int len = str.length();
	bool flag = true;
	memset(b,0,sizeof(b));
	for(int i = 0;i < len;i++){
		if(str[i] == '('){
			st.push(str[i]);
		}else if(str[i] != ')' && str[i] != '('){
			int t = str[i];
			if(b[t] != 0){
				flag = false;
				break;
			}else{
				b[t]++;
			}
		}else if(str[i] == ')'){
			memset(b,0,sizeof(b));
			if(st.size() == 0){
				flag = false;
				break;
			}else{
				st.pop();
			}
		}
	}
	if(flag == false){
		printf("No\n");
	}else{
		printf("Yes\n");
	}
	return 0;
}

E - Don't Isolate Elements

E - Don't Isolate Elements (atcoder.jp)

Solution

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
constexpr int inf = 1000000010;
template<class T, class U> inline bool chmin(T &a, const U &b) { if (a > b) { a = b; return true; } return false; }
int main(){
	int h,w;
	cin>>h>>w;
	vector<vector<int>> a(h,vector<int>(w));
	for(int i = 0;i < h;i++){
		for(int j = 0;j < w;j++){
			cin>>a[i][j];
		}
	}
	vector<vector<vector<int>>> dp(h,vector<vector<int>>(2, vector<int>(2,inf)));
	dp[0][0][0] = 0;
	dp[0][0][1] = 1;
	for(int i = 1;i < h;i++){
		for(int j = 0;j < 2;j++){
			for(int k = 0;k < 2;k++){
				for(int l = 0;l < 2;l++){
					vector<int> x(w,-1);//初始化为-1,为了在i=1时可以作比较
					if(i != 1){
						x = a[i-2];//此时x可以表示矩阵中的一行了
					}
					if(j){//j代表i-2行进行了操作
						for(int m = 0;m < w;m++){
							x[m] = 1-x[m];
						}
					}
					vector<int> y = a[i-1];//表示i-1行
					if(k){//k表示i-1行操作没有
						for(int m = 0;m < w;m++){
							y[m] = 1-y[m];
						}
					}
					vector<int> z = a[i];
					if(l){
						for(int m = 0;m < w;m++){
							z[m] = 1-z[m];
						}
					}
					//3行变完,开始判断是否合法
					bool flag = true;
					for(int m = 0;m < w;m++){
						if(y[m] != z[m] && x[m] != y[m] && (m == 0 || y[m] != y[m-1]) && (m == w-1 || y[m] != y[m+1])){
							flag = false;
						}
					}
					if(i == h-1){
						for(int m = 0;m < w;m++){
							if(z[m] != y[m] && (m == 0 || z[m] != z[m-1]) && (m == w-1 || z[m] != z[m+1])){
								flag = false;
							}
						}
					}//判断完
					if(flag){//假如合法
						chmin(dp[i][k][l],dp[i-1][j][k] + l);//加l判断是否变了
					}
				}
			}
		}
	}
	//dp跑完;
	int ans = inf;
	for(int j = 0;j < 2;j++){
		for(int k = 0;k < 2;k++){
			chmin(ans, dp[h-1][j][k]);
		}
	}
	if(ans == inf){
		cout<<-1<<endl;
	}else{
		cout<<ans<<endl;
	}
	return 0;
}

F - Permutation Distance

F - Permutation Distance (atcoder.jp)

Solution

给出两种解答:
1.双重循环减枝:第一重循环我们对i进行遍历来求Di的值,第二重循环,我们设变量jj表示下一个数组元素对i的相对距离。然后每次进行更新。
作ans = ∞,j = 1。进行下列变换:

\[ans = min(ans,|P_i-P_{i-j}| + j)(当i > j时) \]

\[ans = min(ans,|P_i - P_{i+j}| + j)(当i + j <= n时) \]

然后每次j自增1,当j > ans的时候结束循环输出当前i对应的ansDi

#include <bits/stdc++.h>
using namespace std;
int main(){    
	int N;
    cin >> N;
    vector<int> P(N+1);
    for(int i = 1;i <= N;i++){
    	cin>>P[i];
	}
    for(int i = 1;i <= N;i++){
    	int res = 2*N;
    	for(int j = 1;j <= res;j++){
    		if(i  > j) res = min(res, abs(P[i] - P[i-j]) + j);
    		if(i + j <= N) res = min(res, abs(P[i] - P[j+i]) + j);
		}
		cout<< res <<" ";
	}
	return 0;
}

时间复杂度为\(O(N\sqrt(N))\)

解答2:将题目中的绝对值打开,可以得到四种情况:

\[\begin{aligned} D_i &= \underset {j≠i}{min}​(|P_i-P_j|+|i-j|)\\ &= min\{\underset{j<i}{min}(|P_i- P_j| + i-j),\underset{j>i}{min}(|P_i-P_j|+j-i)\}\\ &= min\{\underset{j<i,P_j<P_i}{min}(P_i-P_j+i-j),\underset{j<i,P_j>P_i}{min}(P_j-P_i+i-j),\underset{j>i,P_j<P_i}{min}(P_i-P_j+j-i),\underset{j>i,P_j>P_i}{min}()P_j-P_i+j-i\}\\ &= min\{P_i+i-\underset{j<i,P_j<P_i}{max}((P_j+j)),\underset{j<i,P_j>P_i}{min}((P_j+j)-(P_i-i)),P_i-i-\underset{j>i,P_j<P_i}{max}((P_j-j)),\underset{j>i,P_j>P_i}{min}((P_j+j)-(P_i+i))\} \end{aligned} \]

#include <iostream>
#include <vector>
#include <atcoder/segtree>
using namespace std;
constexpr int INF = 100000000;
// 设置区间最大线段树
using S = int;
int op(int a, int b) { return max(a, b); }
int e() { return -INF; }
using segtree = atcoder::segtree<S, op, e>;
void calc(const int N, const vector<int> &P, vector<int> &D) {
    // chmin(D[i], P[i] + i - max_{j < i && P[j] < P[i]} {P[j] + j}
    segtree segment_tree(N);
    for (int i = 0; i < N; ++i) {
        D[i] = min(D[i], P[i] + i - segment_tree.prod(0, P[i]));
        segment_tree.set(P[i] - 1, P[i] + i);
    }
}
int main() {
    int N;
    cin >> N;
    vector<int> P(N);
    for (auto &&p : P) cin >> p;
    vector<int> D(N, INF);
    // j < i , P[j] < P[i]
    calc(N, P, D);
    // j < i , P[j] > P[i]
    for (auto &&p : P) p = N + 1 - p;
    calc(N, P, D);
    // j > i , P[j] > P[i]
    reverse(begin(P), end(P));
    reverse(begin(D), end(D));
    calc(N, P, D);
    // j > i , P[j] < P[i]
    for (auto &&p : P) p = N + 1 - p;
    calc(N, P, D);
    // 反转回来
    reverse(begin(P), end(P));
    reverse(begin(D), end(D));
    for (int i = 0; i < N; ++i) cout << D[i] << " ";
    cout << endl;
    return 0;
}

关于AC(AtCoder) Library,看最后。

G - Partial Xor Enumeration

G - Partial Xor Enumeration (atcoder.jp)

这是一道线性基多次求第k大元素的题。套线性基板子就行。

Solution

#include <bits/stdc++.h>
 
using i64 = long long;
 
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    i64 L, R;
    std::cin >> N >> L >> R;
    L--;
    
    std::vector<i64> A(N);
    for (int i = 0; i < N; i++) {
        std::cin >> A[i];
    }
    
    std::array<i64, 60> t{};
    for (int i = 0; i < N; i++) {
        for (int j = 59; j >= 0; j--) {
            if (A[i] >> j & 1) {
                if (t[j]) {
                    A[i] ^= t[j];
                } else {
                    t[j] = A[i];
                    break;
                }
            }
        }
    }
    
    for (int i = 59; i >= 0; i--) {
        if (t[i]) {
            for (int j = i + 1; j < 60; j++) {
                if (t[j] >> i & 1) t[j] ^= t[i];
            }
        }
    }
    
    for (i64 i = L; i < R; i++) {
        i64 ans = 0;
        i64 x = i;
        for (int j = 0; j < 60; j++) {
            if (t[j]) {
                if (x & 1) ans ^= t[j];
                x /= 2;
            }
        }
        std::cout << ans << " \n"[i == R - 1];
    }
    
    return 0;
}

Ex - Popcount Sum

Ex - Popcount Sum (atcoder.jp)

这道题是求在\(1-N\)中模\(M\)等于\(R\)的整数的二进制表示中,\(1\)的个数的和。
现在有下面一条结论:

对于正整数\(A\),他的\(2^k\)位为1
\(2^k <= (A mod 2^{k+1} < 2^{k+1})\)
\(\left[\frac{A+2^k}{2^{k+1}}\right]-\left[\frac{A}{2^{k+1}}\right]=1\)

上面三条性质等价,我们可以将问题转化为第三条性质来做,所以可以利用atcoder的内部函数floor_sum来做。

注意:floor_sum函数是用来求解:
$ \sum_{i=0}^{n-1} \lfloor \frac{ai+b}{m} \rfloor 的值, a,b\geq 0 , n,m > 0$

Solution

#include<atcoder/all>
#define int long long 
using namespace std;
int t,n,m,r;
signed main(){
	ios::sync_with_stdio(0);
	for(cin>>t;t--;){
		cin>>n>>m>>r;
		int t=(n-r)/m+1,res=(r+r+(t-1)*m)*t/2; 
		for(int i=2;i<=n;i<<=1)
			res-=atcoder::floor_sum(t,i,m,r);
		cout<<res<<"\n";
	}
}

最后

关于AC(AtCoder) Library的安装使用参考这篇博客:AC(AtCoder) Library 文档翻译

posted @ 2022-12-31 20:01  TTS-S  阅读(43)  评论(0编辑  收藏  举报