这是准备第一次打正式的区域赛前模拟做的一套题,作为比赛前的最后一次模拟训练。希望自己在比赛上不拖队友后腿(队友tql),能够发挥一个作为数学和数据结构选手的作用。
也希望自己在接下来的ACM生涯中能够
以梦为马,不负韶华。
F题 Friendship of Frog
本题便是全场的签到题,不多赘述。线性处理,记录上一个位置即可。
//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>0
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
ll a, b, mod;
inline int read(){
char c=getchar();
int x=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
int pos[26];int Case = 0;
char s[N];
void solve(){
cin>>s+1;
int ans = INF;
for(int i = 0; i <=25; ++i)pos[i] = 0;
for(int i = 1; i <= strlen(s+1); ++i){
if(!pos[s[i]-'a'])pos[s[i]-'a'] = i;
else {
ans = min(ans,i - pos[s[i]-'a']);
pos[s[i]-'a'] = i;
}
}
if(ans == INF)ans = -1;
cout<<"Case #"<<Case<<": "<<ans<<'\n';
}
int main(){
//ios::sync_with_stdio(0);
//cin.tie(0);
//cout.tie(0);
#ifdef ACM
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
t = 1;
//srand((unsigned)time(NULL));
scanf("%lld",&t);
while (t--){
++Case;
solve();
}
fclose(stdin);
fclose(stdout);
}
K题 Kingdom of Black and White
思维题。还是蛮好做的,就是被long long 卡了半天,明明N有1e5,我还开了int,我太菜了。
本题主要就是分析一下两种情况,要么是两个连续的不同颜色的串,我们去更改一个端点,要么就是改变一个点,然后将左右两侧相连。
预处理每个变色的端点左右两侧的连续串长度即可,复杂度O(n)。
当然其实也可以直接单独把每一串长度单独保存,可以更加方便的处理,常数更优。
//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
inline int read(){
char c=getchar();
int x=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
ll l[N], r[N];
char s[N];
int Case;
void solve(){
cin>>s+1;
ll len = strlen(s+1);
ll ans = 0;
ll nowlen = 1;
for(int i = 0; i <= len ;++i)l[i] = r[i] = 0;//其实可以去掉(
for(int i = 2; i <= len; ++i){//预处理左边
if(s[i] != s[i-1]){
l[i-1] = nowlen;
nowlen = 1;
} else ++nowlen;
}
nowlen = 1;
for(int i = len-1 ; i >= 1; --i){//预处理右侧
if(s[i] != s[i+1]){
r[i+1] = nowlen;
nowlen = 1;
} else ++nowlen;
}
nowlen = 1;
for(int i = 2; i <= len ; ++i){//先获取本来的总和
if(s[i] != s[i-1]){
ans += nowlen * nowlen;
nowlen = 1;
} else ++nowlen;
}
ans += nowlen * nowlen;
ll res = 0;
for(int i = 2; i <= len ;++i){//寻找最优修改点
if(i < len && s[i] != s[i-1] && s[i] != s[i+1]){
res = max(res,(ll)(2*r[i+1]*l[i-1]+2*(l[i-1]+r[i+1])));
} else if(s[i] != s[i-1]){
int llen = l[i-1], rlen = r[i];
res = max(res,2*1ll*(abs(llen-rlen+1)));
}
}
ans += res;
cout<<"Case #"<<Case<<": "<<ans<<'\n';
}
int main(){
//ios::sync_with_stdio(0);
//cin.tie(0);
//cout.tie(0);
#ifdef ACM
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
t = 1;
//srand((unsigned)time(NULL));
scanf("%lld",&t);
while (t--){
++Case;
solve();
}
fclose(stdin);
fclose(stdout);
}
L题 LCM Walk
这是一道比较简单的数论题。我们只需要仔细的倒着推即可,且大致可以估算复杂度比较低(以下解法我无法给出一个比较准确的复杂度,因为我实在是太菜了,大佬们可以自己证明,或着查询其他文章)。
对于这题,我们直接考虑最后一步,注意到每一步都走一个LCM,即:增加的那个坐标一定是接下来那个坐标对中的较大者。我们去分析上一步,然后我们将每一个数都看成最大公约数乘上一个数的形式即可。
//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
inline int read(){
char c=getchar();
int x=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
ll gcd(ll a,ll b){
ll res;
while(b){
res = a % b;
a = b;
b = res;
}
return a;
}
ll lcm(ll a,ll b){return a * b / gcd(a,b);}
ll ex, ey;
ll ix, iy;
int Case;
void solve(){
cin>>ex>>ey;
ll ans = 1;
while(1){
if(ex > ey)swap(ex,ey);
ll g = gcd(ex,ey);
ll ix = ex + g;
if(ey % ix == 0){
ey = ey * g / ix;
++ans;
}
else break;
}
cout<<"Case #"<<Case<<": "<<ans<<'\n';
}
int main(){
//ios::sync_with_stdio(0);
//cin.tie(0);
//cout.tie(0);
#ifdef ACM
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
t = 1;
//srand((unsigned)time(NULL));
scanf("%lld",&t);
while (t--){
++Case;
solve();
}
fclose(stdin);
fclose(stdout);
}
A题是道几何体,姑且先咕咕咕了。。。
B题 Binary Tree
这是一道不错的思维题,考察了对二进制的理解。这题卡了我大半天,我实在太菜了。
解题思路:
首先我们需要充分利用题目给我们的信息,提示。比如数据范围?这题的突破口就在于数据范围,我们注意到有2^k>=n,且我们必须走k层,如果我们走k层,把每一层的和加起来,那么最小值就是一直往左边走的情况,即pow(2,k)-1,而如果在最后一层选择向右走,则有pow(2,k),直觉上似乎我们只需要一直向左走就可以了,不然的话,这题不仅很难考虑,而且数据范围也不是特别有必要。我们思考,如果我们先向左走,每个值都加起来,然后我们思考,如果我们减去一个数,会导致当前的和变为nowsum - nowsub*2,由于我们一直往左走,所以路径上每一个值都是二的整数幂,如果我们考虑可以减去任意二次幂的和,那么我们就可以构造出任何一个被减数,由于乘2buff导致我们所有的若干二次幂的和乘2,这样就导致了1无法单独减去,而其他任意小于当前总和的数都可以减去,在考虑道最后一层的1,我们就可以随意支配了。
//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
ll k;
inline int read(){
char c=getchar();
int x=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
int Case;
ll fast(ll a, ll b){
ll res = 1;
while(b){
if(b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
void solve(){
cin>>n>>k;
printf("Case #%d:\n",Case);
int f = 0;
if(n & 1) f = 1;//奇偶判断
else n --;//如果为偶数,就先转化为奇数的情况,方便最后一层的处理
ll sum = fast(2,k) - 1;//奇数情况的和
ll d = sum - (sum - n) / 2;
ll res = 1;
while(d > 1){
if(d & 1)cout<<res<<" +\n";
else cout<<res<<" -\n";
d >>= 1;
res *= 2;
}
if(f)cout<<res<<" +\n";
else cout<<res+1<<" +\n";
}
int main(){
//ios::sync_with_stdio(0);
//cin.tie(0);
//cout.tie(0);ertg
#ifdef ACM
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
t = 1;
//srand((unsigned)time(NULL));
scanf("%lld",&t);
while (t--){
++Case;
solve();
}
fclose(stdin);
fclose(stdout);
}
由于最后一天比较累(只睡了两三个小时,题解写的仓促,逻辑有很多问题),但暂时不改了。