Codeforces 1016
A - Ideal Generator
题目:
非常简单,从样例都可以看出只要 k k k 是奇数就是,反之不是。
因为当 k k k 为奇数时,这个回文数中间有一个单独的数,这个数可以是任意一个数,所以很容易满足回文,但如果是偶数,就要严格满足一 一对应关系,所以明显有数不行。
代码过分简单,读者自己写。(lazy~)
B - Expensive Number
题目:
很明显,我们首先要找出最小代价是多少。很明显是 1 1 1,也就是当这个数本身与各个数位上的数相加后的和相等时成立。
那在什么时候这个条件会成立?答案是只有一位数字时。这个也很明显,在此不多做讨论。
那么这道题改一下就成了这样:
给你一个数,让你删掉一些数位上的数使得这个数最终是一个一位数,求删掉的最少数量。
因为题目中允许有前导 0 0 0,所以对于一个数位 i i i,它前面只需要删掉不是 0 0 0 的数,而后面则需要全部删掉。
现在我们要让这个删掉的数位数量最少,那我们就要确定一个 i i i 使得它最小。那我们又该在什么时候开始删呢?
我们找删除数位这个过程中最特殊的情况:前面只需要删掉不是 0 0 0 的数。那么我们让尽可能多的 0 0 0 在前面不就行了?反过来说,我们要找的这个 i i i 是从后往前第一个不是 0 0 0 的那一位。
然后就 A C \color{green}{AC} AC 了!
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 2e18
const ll mod=1e9+7;
namespace io {
using namespace std;
inline ll read() {
char n=getchar();
ll num=0,flag=1;
while(n<'0'||n>'9') {
if(n=='-') {
flag=-1;
}
n=getchar();
}
while(n>='0'&&n<='9') {
num=num*10+n-'0';
n=getchar();
}
return num*flag;
}
inline void print(ll x) {
if(x<0) {
putchar('-');
print(-x);
return;
}
if(x==0) {
return;
}
print(x/10);
putchar((char)(x%10+'0'));
}
}
using namespace io;
const ll N=1e2+5;
ll T,n[N],cnt,ans;
double k=inf;
string s;
map<char,bool> mp;
bool f;
void solve() {
cin>>s;
if(s.size()==1) {
cout<<0<<endl;
return ;
}
cnt=0;
f=0;
for(ll i=s.size()-1;i>=0;i--) {
if(s[i]=='0') {
if(!f) cnt++;
}
else {
f=1;
cnt++;
}
}
cout<<cnt-1<<endl;
}
int main(){
T=read();
while(T--) {
solve();
}
return 0;
}
C - Simple Repetition
题目:
这道题也是毁常的简单啊。
对于 x x x 与 k k k,我们可以按照它们的特殊性把它们分成三类: { x ≠ 1 , k = 1 x = 1 , k ≠ 1 x ≠ 1 , k ≠ 1 \begin{cases}x\not=1,k=1\\x=1,k\not=1\\x\not=1,k\not=1\end{cases} ⎩ ⎨ ⎧x=1,k=1x=1,k=1x=1,k=1。
1. x ≠ 1 , k = 1 x\not=1,k=1 x=1,k=1
这种时候最简单,只需要判断 x x x 是不是质数就行了。
2. x = 1 , k ≠ 1 x=1,k\not=1 x=1,k=1
这种情况稍微有点复杂,我们可以通过列举来看看哪些是质数、哪些是合数:
其实通过找规律我们也能很明显的看出:当 k = 2 k=2 k=2 时是质数,其余情况都不是,具体证明我也不会,会证明的读者麻烦在评论区展示一下。
3. x ≠ 1 , k ≠ 1 x\not=1,k\not=1 x=1,k=1
这种情况也很简单,因为由 k k k 个 x x x 所组成的数必然能拆成 x × 1 0000 … 1 ⏟ x 的位数 … ⏟ k − 1 个 x\times1\underbrace{\underbrace{0000\dots1}_{x\text{的位数}}\dots}_{k-1\text{个}} x×1k−1个 x的位数 0000…1…,因此它必然是合数。
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 2e18
const ll mod=1e9+7;
namespace io {
using namespace std;
inline ll read() {
char n=getchar();
ll num=0,flag=1;
while(n<'0'||n>'9') {
if(n=='-') {
flag=-1;
}
n=getchar();
}
while(n>='0'&&n<='9') {
num=num*10+n-'0';
n=getchar();
}
return num*flag;
}
inline void print(ll x) {
if(x<0) {
putchar('-');
print(-x);
return;
}
if(x==0) {
return;
}
print(x/10);
putchar((char)(x%10+'0'));
}
}
using namespace io;
const ll N=1e2+5;
ll T,k,n;
string s;
ll sspd(ll x) {
if(x==1) return false;
for(ll i=2;i<=x/i;i++) {
if(x%i==0) return false;
}
return true;
}
void solve() {
cin>>n;
s=to_string(n);
cin>>k;
if(n==1) {
if(k==2) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
else if(k>1) {
cout<<"NO"<<endl;
}
else if(k==1) {
if(sspd(n)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
int main(){
T=read();
while(T--) {
solve();
}
return 0;
}
D - Skibidi Table
题目:
一道很简单的分治,这里我就不过多赘述了,大家自己推一下函数,也没什么难的,反正代码在下面:
#include <bits/stdc++.h>
#define ll long long
namespace io {
using namespace std;
inline ll read() {
char n=getchar();
ll num=0,flag=1;
while(n<'0'||n>'9') {
if(n=='-') {
flag=-1;
}
n=getchar();
}
while(n>='0'&&n<='9') {
num=num*10+n-'0';
n=getchar();
}
return num*flag;
}
inline void print(ll x) {
if(x<0) {
putchar('-');
print(-x);
return;
}
if(x==0) {
return;
}
print(x/10);
putchar((char)(x%10+'0'));
}
}
using namespace io;
ll T,n,q;
string op;
struct node {
ll x,y;
};
ll dfs1(ll id,ll l,ll r,ll x,ll y) {
if(l==x&&r==y) {
return 1;
}
ll dt=1<<(id-1);
ll dd=dt*dt;
if(x>=l+dt&&y>=r+dt) {
return dd+dfs1(id-1,l+dt,r+dt,x,y);
}
if(x>=l+dt) {
return (dd<<1)+dfs1(id-1,l+dt,r,x,y);
}
if(y>=r+dt) {
return dd*3+dfs1(id-1,l,r+dt,x,y);
}
return dfs1(id-1,l,r,x,y);
}
node dfs2(ll id,ll l,ll r,ll d) {
if(d==1) {
return (node){l,r};
}
ll dt=1<<(id-1);
ll dd=dt*dt;
if(d>3*dd) {
return dfs2(id-1,l,r+dt,d-3*dd);
}
if(d>(dd<<1)) {
return dfs2(id-1,l+dt,r,d-(dd<<1));
}
if(d>dd) {
return dfs2(id-1,l+dt,r+dt,d-dd);
}
return dfs2(id-1,l,r,d);
}
void solve() {
n=read();
q=read();
while(q--) {
ll x,y;
cin>>op;
x=read();
if(op[0]=='-') {
y=read();
ll ans=dfs1(n,1,1,x,y);
if(ans==0) putchar('0');
print(ans);
}
else {
node ans=dfs2(n,1,1,x);
if(ans.x==0) putchar('0');
print(ans.x);
putchar(' ');
if(ans.y==0) putchar('0');
print(ans.y);
}
putchar('\n');
}
}
int main() {
T=read();
while(T--) {
solve();
}
return 0;
}
E - Min Max MEX
题目:
首先我们明确一点: MEX \operatorname{MEX} MEX 的定义。
MEX \operatorname{MEX} MEX 指一串自然数里面没出现的最小非负整数。而题目然我们求最大的 MEX \operatorname{MEX} MEX,这听上去是不是很耳熟?对了,最小的最大!
一眼算法:二分。
然后重点就在于判断函数怎么写。
既然直接硬钢不好做,我们反着来。我们不是二分出了一个当前的 MEX \operatorname{MEX} MEX 吗,为什么我们不用当前二分出来的这个 MEX \operatorname{MEX} MEX 来反过来算要割成几份呢?然后再验证一下个数是不是大于等于 k k k 就对了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 2e18
const ll mod=1e9+7;
namespace io {
using namespace std;
inline ll read() {
char n=getchar();
ll num=0,flag=1;
while(n<'0'||n>'9') {
if(n=='-') {
flag=-1;
}
n=getchar();
}
while(n>='0'&&n<='9') {
num=num*10+n-'0';
n=getchar();
}
return num*flag;
}
inline void print(ll x) {
if(x<0) {
putchar('-');
print(-x);
return;
}
if(x==0) {
return;
}
print(x/10);
putchar((char)(x%10+'0'));
}
}
using namespace io;
const ll N=2e5+5;
ll T,n,k,a[N];
bool ck(ll x) {
vector<ll> mp(x+5,0);
ll cnt=0,pos=0;
for(ll i=1;i<=n;i++) {
if(a[i]<x&&!mp[a[i]]) {
mp[a[i]]=1;
pos++;
}
if(pos>=x) {
cnt++;
pos=0;
for(ll j=0;j<=x;j++) {
mp[j]=0;
}
}
}
if(cnt>=k) {
return true;
}
return false;
}
void solve() {
n=read();
k=read();
for(ll i=1;i<=n;i++) {
a[i]=read();
}
ll l=0,r=n,ans=0;
while(l<r) {
ll mid=(l+r+1)>>1;
if(ck(mid)) {
l=mid;
ans=mid;
}
else {
r=mid-1;
}
}
if(!ans) putchar('0');
else print(ans);
cout<<endl;
}
int main() {
T=read();
while(T--) {
solve();
}
return 0;
}
F - Hackers and Neural Networks
题目:
说句实话:我一开始看到这道题连样例都没看懂,后面经过大佬指点后才明白了这道题的真正含义,实在是有点奇怪,让我来给你“翻译”一下:
最初,黑客们有一个长度为 n n n 的序列 c c c,而 c c c 初始为空,在第一次操作中,它需要选择一个 b i b_i bi 使它自己等于 b i b_i bi,然后再按照上面的规则进行替换,问最少操作次数。
(其实我也不知道题目怎么叙述着叙述着就成这样了……)
那这下意思就很简单了啊,用个贪心找到与 a a a 共同点最多的,记录下来,然后初始化就等于这个字符串,最后再按照上面的操作一顿操作就行了。
那如何判断 − 1 -1 −1 的情况?也很简单,你想:如果你把所有的字符串都用完了还是不能凑出 a a a,那不就凉了吗?反之就没事,所以加个标记数组就完事。
代码:
#include<bits/stdc++.h>
#define ll long long
namespace io {
using namespace std;
inline ll read() {
char n=getchar();
ll num=0,flag=1;
while(n<'0'||n>'9') {
if(n=='-') {
flag=-1;
}
n=getchar();
}
while(n>='0'&&n<='9') {
num=num*10+n-'0';
n=getchar();
}
return num*flag;
}
inline void print(ll x) {
if(x<0) {
putchar('-');
print(-x);
return;
}
if(x==0) {
return;
}
print(x/10);
putchar((char)(x%10+'0'));
}
}
using namespace io;
const ll N=5e2+5;
ll n,m,k,t,cnt,num[N],ans;
bool f;
string a[N],b[N][N];
int main() {
cin>>t;
while(t--) {
memset(num,0,sizeof(num));
cin>>n>>m;
f=0,ans=0,cnt=0;
for(ll i=1;i<=n;i++) {
cin>>a[i];
}
for(ll i=1;i<=m;i++) {
for(ll j=1;j<=n;j++) {
cin>>b[i][j];
}
}
for(ll i=1;i<=m;i++) {
for(ll j=1;j<=n;j++) {
if(b[i][j]==a[j]) {
cnt++;
num[j]=1;
}
}
ans=max(ans,cnt);
cnt=0;
}
for(ll i=1;i<=n;i++) {
if(num[i]==0) {
f=1;
}
}
if(!f) {
cout<<n+2*(n-ans);
}
else {
cout<<"-1";
}
cout<<endl;
}
return 0;
}
G - Shorten the Array
题目:
(瞅我干啥,我不会。)
按照我们机房里另一位大佬的写法,这题应该是一个 Trie 树(字典树),但我不会……