Codeforces Round #739 (Div. 3)(补题)

A:

直接暴力枚举


const int N=1111122;
const int M=200005;
int ok(int x) {
	if(x%10==3)return 1;
	if(x%3==0)return 1;
	return 0;
}
int is(int n) {
	int x = 0;
	while(n) {
		x ++;
		if(!ok(x))n --;
	} 
	return x;
}
int main() {
	int T,i,j,n,m;
	cin >> T;
	while(T--) {
		cin >> n;
		cout << is(n)  << endl;
	} 
	return 0;
} 

B:

分类讨论即可

const int N=1111122;
const int M=200005;
int main() {
	ll T,i,j,n,m,a,b,c;
	cin >> T;
	while(T--) {
		cin >> a >> b >> c;
		ll M = max(a,b);
		ll x = abs(a - b);
		if(M > x * 2) {
			cout << -1 << endl;
			continue;
		}
		if(c > x * 2)cout << -1 << endl;
		else {
			if(c <= x)cout << c + x << endl;
			else cout << (c + x) % (x * 2) << endl;
		}
	}
}

C:

先找位于的列数,发现规律1 2 5 10…,然后找位于的行数,暴力即可

const int N=1111122;
const int M=200005;
void solve(ll n) {
	ll x = 1 , i , sum = 0;
	for(i=1;i;i) {
		x ++;
		sum += i;
		if(sum >= n)break;
		i += 2;
	}
	x --;
	sum -= i;
	int y = n - sum;
	if(y <= x) {
		cout << y << ' ' << x << endl;
	}
	else {
		y -= x;
		cout << x << ' ' << x - y << endl;
	}
}
int main() {
	ll T,i,j,n,m;
	cin >> T;
	while(T--) {
		cin >> n;
		solve(n);
	} 
}

D:

枚举从2的0次幂枚举到63次幂(因为可能后面某个数字的贡献更小),然后按顺序找最长的公共前缀,注意一定要按顺序(刚开始写了个最长公共子序列,这样是不对的,比如1045 和1024,公共长应该是2而不是3),答案就是需要加末尾的和需要删的之和

#define inf 0x3f3f3f3f
const int N=1111122;
const int M=200005;
int f[20][20],s1[20],s2[20];
ll a[1000];
int o,u;
void init() {
	ll x = 1;
	for(int i = 0 ; i <= 63 ; i ++) {
		a[i] = x; 
		x *= 2;
	}
}
int lcs() {
	int x = o , i;
	for(i=u;i>=1;) {
		if(s1[x] == s2[i]) {
			i --;
			x --;
		}
		else x --;
		if(x < 1)break;
	}
	return u - i;
}
int check(ll n,int c) {
	ll x = a[c];
	ll y = n;
	o = 0 , u = 0;
	while(y > 0) {
		s1[++o] = y % 10;
		y /= 10;
	}
	while(x > 0) {
		s2[++u] = x % 10;
		x /= 10;
	}
	int res = lcs();
	return o - res + u - res;
}
int main() {
	ll T,i,j,n,m;
	cin >> T;
	init();
	while(T--) {
		cin >> n;
		int Min = inf;
		for(i = 0 ; i <= 63 ; i ++) {
			Min = min(Min , check(n , i));
		}
		cout << Min << endl;
	}
}

E:

我们很容易得到在原字符串中每种字符的数量,由此从后往前进行枚举,得到一个字符串,然后进行check()该字符串,看他按照题目的描述得到的最终字符串和给的S是否一样

char s[N];
int flag,Mi,o,u,n;
int num[M],v[M],a[M],v2[M],s1[N],s2[N];
void ACM(int x,int y) {
    int ans = num[a[y]];
    for(int i = x ; i >= 0 ; i --) {
        Mi = min(Mi , i);
        if(s[i] == a[y])ans --;
        if(ans == 0)return ;
    }
    if(ans)flag = 1;
}
void check() { 
	int len = u;
	for(int i = o ; i >= 1 ; i --) {
		v2[a[i]] = 1;
		for(int j = 0 ; j < len ; j ++) {
			if(!v2[s2[j]])s1[u ++] = s2[j];
		}
	}
	if(u != n)flag = 1;
	for(int i = 0 ; i < u ; i ++) {
		if(s1[i] != s[i])flag = 1;
	}
	if(flag) {
		cout << -1 << endl;
	}
	else {
		for(int i = 0 ; i <= Mi ; i ++)printf("%c",s1[i] + 'a');
		cout << ' ';
		for(int i = o ; i >= 1 ; i--)printf("%c",a[i] + 'a');
		cout << endl;
	}
}
void solve() {
    set<char> st;
    int ans = 0,flag = 0;
    n = strlen(s);
    for(int i = n - 1 ; i >= 0 ; i --) {
        s[i] -= 'a';
        if(!v[s[i]])a[++ o] = s[i],v[s[i]] = 1;
        num[s[i]] ++;
    }
    for(int i = 1 ; i <= o ; i ++) {
        if(num[a[i]] % (o - i + 1))flag = 1;
        num[a[i]] = num[a[i]] / (o - i + 1);
    }
    Mi = n - 1;
    int x;
    for(int i = 1 ; i < o ; i ++) {
        x = Mi;
        for(int j = 1 ; j <= i ; j ++) {
            ACM(x , j);
        }
        Mi --;
    }
    for(int i = 0 ; i <= Mi ; i ++) {
        num[s[i]] --;
    }
    for(int i = 0 ; i < 26 ; i ++){
        if(num[i] != 0)flag = 1;
    }
    if(flag)cout << -1 << endl;
    else {
        for(int i = 0 ; i <= Mi ; i ++)
        s1[u ++] = s[i] , s2[i] = s[i];
        check();
    }
}
int main() {
    int T;
    cin >> T;
    while(T --) {
        memset(v , 0 , sizeof v);
        memset(v2 , 0 , sizeof v2);
        memset(num , 0 , sizeof num);
        flag = 0;o = 0,u = 0;
        cin >> s;
        solve();
    }
    return 0;
}

F1

赛中一直在分类讨论,越讨论情况越多…;赛后看别人用的二进制枚举,因为只可能包含两种数字,那么就枚举0~9种的任意两个数字,然后塞到set里,用st.lower_bound(),即可,注意不能直接用泛化函数lower_bound(),会直接超时

const int N = 1010;
const int M = 20010;
set<ll> st1,st2;
void init() {
    for(int i = 1 ; i <= 9 ; i ++) {
        ll ans = 0;
        for(int j = 1 ; j <= 10 ; j ++) {
            ans = ans * 10 + i;
            st1.insert(ans);st2.insert(ans);
        }
    }
    for(int i = 0 ; i <= 9 ; i ++) {
        for(int j = i + 1 ; j <= 9 ; j ++) {
            for(int k = 1 ; k < (1 << 10) ; k ++) {
                ll ans = 0;
                for(int g = 0 ; g <= 10 ; g ++) {
                    if(k & (1 << g))ans = ans * 10 + i;
                    else ans = ans * 10 + j;
                    st2.insert(ans);
                }
            }
        }
    }
}
int main() {
    int T;cin >> T;
    init();
    while(T --) {
        ll n,k;
        cin >> n >> k;
        if(k == 1)cout << *st1.lower_bound(n) << endl;
        else cout << *st2.lower_bound(n) << endl;
    }
    return 0;
}

F2

对于一个数,如果第q位是第k+1种数字,那么假如第q位不是9,那么直接s[q]++,然后后面全部置为0即可,如果第q位是就,那么就往前找第一个不是9的,s[q]++;当然,一步得到的可能不是满足条件的,然后我们继续进行上述操作,直到满足条件

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define IO ios::sync_with_stdio(false)
#define bug cout << "-----\n"
typedef long long ll;
int Mod = 1000000007;
const int N = 500010;
const int M = 50;
char s[M];
int k;
set<char> st;
void solve() {
    st.clear();
    int n = strlen(s);
    while(1) {
        st.clear();//注意清st,否则超时
        for(int i = 0 ; i < n ; i ++)
            st.insert(s[i]);
        if(st.size() <= k)
            break;
        st.clear();
        int idx = 0;
        while(st.size() <= k) {
            st.insert(s[idx ++]);
        }
        while(s[--idx] == '9');
        ++s[idx];
        for(int i = idx + 1 ; i < n ; i ++)s[i] = '0';
    }
    cout << s << '\n';
}
int main() {
    IO;
    int T;
    cin >> T;
    while(T --) {
        cin >> s >> k;
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值