前言
现在也是好起来了,能经常切E了!>v<
这么看我们新生赛的难度差不多也就abc里D或者E的难度,不知道为啥自己能开得那么慢,也许是客场作战+太冷+赛时红温的原因(?
一、A - o-padding
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int n;
cin>>n;
string s;
cin>>s;
while(s.length()<n)
{
s="o"+s;
}
cout<<s<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
纯模拟,只要长度不够就往前补就行。
二、B - Magic Square
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int n;
cin>>n;
vector<vector<int>>g(n,vector<int>(n));
g[0][(n-1)/2]=1;
int x=0;
int y=(n-1)/2;
int k=2;
while(k<=n*n)
{
if(g[(x-1+n)%n][(y+1)%n]==0)
{
g[(x-1+n)%n][(y+1)%n]=k++;
x=(x-1+n)%n;
y=(y+1)%n;
}
else
{
g[(x+1)%n][y]=k++;
x=(x+1)%n;
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<g[i][j]<<" ";
}
cout<<endl;
}
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
这个题也还好,直接根据题意模拟着填就可以了,反正说可以证明一定能全填上。
三、C - 2x2 Placing
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int n,m;
cin>>n>>m;
set<pii>st;
auto check=[&](int x,int y)->bool
{
if((st.find({x,y})==st.end())&&(st.find({x+1,y})==st.end())&&(st.find({x,y+1})==st.end())&&(st.find({x+1,y+1})==st.end()))
{
return true;
}
return false;
};
int x,y;
while(m--)
{
cin>>x>>y;
if(check(x,y))
{
st.insert({x,y});
st.insert({x+1,y});
st.insert({x,y+1});
st.insert({x+1,y+1});
}
}
cout<<st.size()/4<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
这个题因为n很大,所以肯定就不能直接模拟了。那么就可以考虑用set维护之前涂过色的格子,所以每次只需要check一下当前要覆盖的四个格子是否以前被涂过色了。如果没有就往set里加上当前操作涂的四个格子,那么时间空间复杂度就都是和操作数相关的了。
四、D - Teleport Maze
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int n,m;
cin>>n>>m;
vector<string>g(n);
for(int i=0;i<n;i++)
{
cin>>g[i];
}
map<char,vector<pii>>mp;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(g[i][j]>='a'&&g[i][j]<='z')
{
mp[g[i][j]].push_back({i,j});
}
}
}
queue<pii>q;
q.push({0,0});
vector<vector<int>>vis(n,vector<int>(m));
vis[0][0]=1;
int level=0;
while(!q.empty())
{
int sz=q.size();
for(int i=1;i<=sz;i++)
{
auto [x,y]=q.front();
q.pop();
if(x==n-1&&y==m-1)
{
cout<<level<<endl;
return ;
}
for(int j=0;j<4;j++)
{
int nx=x+dx[j];
int ny=y+dy[j];
if(nx>=0&&nx<n&&ny>=0&&ny<m&&g[nx][ny]!='#'&&!vis[nx][ny])
{
q.push({nx,ny});
vis[nx][ny]=1;
}
}
if(g[x][y]>='a'&&g[x][y]<='z')
{
vector<pii>next;
for(auto [nx,ny]:mp[g[x][y]])
{
if(!vis[nx][ny])
{
q.push({nx,ny});
vis[nx][ny]=1;
next.push_back({nx,ny});
}
}
mp[g[x][y]]=next;
}
}
level++;
}
cout<<-1<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
这个题其实也就是bfs的板子题。由于存在"传送门",所以首先考虑统计每个字符出现的所有格子,然后就去跑bfs。按层进行bfs的过程中,每次除了考虑上下左右四个方向的格子,如果当前格子是字母,那么就可以传送到别的格子,那么每次就是考虑所有能到的格子里没vis过的,然后下一次碰到这个字母时就只需要考虑这些没vis过的格子即可。
不加最后的判vis更新感觉会TLE,没试过,vp的时候直觉告诉我应该加就直接加了()
五、E - Minimum Swap
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
const int MAXN=3e5+5;
vector<int>father(MAXN);
vector<ll>sz(MAXN);
int n;
void build()
{
for(int i=1;i<=n;i++)
{
father[i]=i;
sz[i]=1;
}
}
int find(int i)
{
if(i!=father[i])
{
father[i]=find(father[i]);
}
return father[i];
}
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
father[fx]=fy;
sz[fy]+=sz[fx];
}
}
void solve()
{
cin>>n;
build();
for(int i=1,x;i<=n;i++)
{
cin>>x;
merge(i,x);
}
ll ans=0;
for(int i=1;i<=n;i++)
{
if(i==find(i))
{
ans+=sz[i]+(sz[i]*(sz[i]-3))/2;
}
}
cout<<ans<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
这题一眼上去确实有点可怕,但其实多举几个例子玩一下会发现其实还好。
对于当前位置i上的数a[i],考虑建立一条(i,a[i])的边,由于是排列,那么肯定会形成若干个环。之后还是举大量例子观察可以发现,对于每个环形成的这个多边形,第一步选择任意两点交换必然可以达到最优解。那么若这个环的大小为n,能形成的方案数就是n*(n-1)/2。那么就只需要用并查集连边,记录每个连通块的大小,然后考虑每个连通块即可,因为必然构成环。
不懂vp的时候为什么用的这个公式,可能想的是除了原本环上的边还能连几条吧,反正这俩公式也是一样的()
六、F - Starry Landscape Photo
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
const int MAXN=5e5+5;
vector<int>tree(MAXN);
int lowbit(int i)
{
return i&-i;
}
void add(int i,int v,int n)
{
while(i<=n)
{
tree[i]+=v;
i+=lowbit(i);
}
}
int sum(int i)
{
int ans=0;
while(i>0)
{
ans+=tree[i];
i-=lowbit(i);
}
return ans;
}
void solve()
{
int n;
cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
//考虑枚举星星最大值为k时的方案数
//那么在找到k这颗星星的位置后,因为此时只能拍到小于等于k的星星
//所以在左右分别找出小于等于k的星星个数x和y个,此时对答案的贡献就是(x+1)*(y+1)
ll ans=0;
for(int i=1;i<=n;i++)
{
//a[i]左侧小于a[i]的个数
ll pre=sum(a[i]);
ans+=(pre+1)*(a[i]-pre);
add(a[i],1,n);
}
cout<<ans<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
其实这题就是一眼方法是需要考虑固定一个,然后去找另外两个的类型,但vp的时候光往固定右端点考虑了,压根没往固定b的方向想,思维还是太僵化了......
考虑枚举星星最大值为k时对答案的贡献,那么在找到亮度为k的这颗星星的位置后,因为此时只能拍到亮度小于等于k的星星,所以在左右找出亮度小于k的星星个数分别为left和right,此时对答案的贡献就是(left+1)*(right+1)。那么就可以考虑用树状数组维护,在从左往右枚举的过程中,对于当前星星的亮度a[i],树状数组里小于等于a[i]的个数就是左侧小于的个数pre,那么右侧小于的个数就是a[i]-pre-1,相乘统计贡献即可。
总结
还得练,希望寒假能练出稳切F的水平!加油!