2021天梯赛题解+总结
L1-1(签到题,略过)
L1-2(输出n-m*k)
L1-3(分情况判断)
L1-4(枚举判断)
L1-5
把所有数都存入数组里面,按下标取然后判断就行了。
L1-6
第一发过了14分就没管,赛后check原代码发现有个bug当时没注意。
注意不能
m
=
=
0
m==0
m==0时立刻输出,还需要判断一下当前串是否能跳过。
判断串直接用C++中string自带的find函数即可,
注意判断是否到结尾是用
s
[
i
]
.
f
i
n
d
(
"
q
i
a
n
d
a
o
"
)
=
=
s
[
i
]
.
n
p
o
s
s[i].find("qiandao")==s[i].npos
s[i].find("qiandao")==s[i].npos实现。
代码
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define sc(x) scanf("%d",&x);
#define scl(x) scanf("%lld",&x);
#define rp(i,s,t) for(int i=(s);i<=(t);i++)
#define RP(i,s,t) for(int i=(s);i>=(t);i--)
#define outval(x) printf("%d\n",x);
#define outval2(x,y) printf("%d %d\n",x,y);
#define outval3(x,y,z) printf("%d %d %d\n",x,y,z);
#define pY puts("Yes")
#define pN puts("No")
using namespace std;
const int N = 1e5+7;
const int INF = 0x3f3f3f3f;
string s[37];
int main(){
// freopen("r","in.txt",stdin);
int n,m;cin>>n>>m;
getchar();
rp(i,1,n) getline(cin,s[i]);
rp(i,1,n){
if(m==0&&s[i].find("easy")==s[i].npos&&s[i].find("qiandao")==s[i].npos){
cout<<s[i]<<endl;
return 0;
}
if(s[i].find("easy")==s[i].npos&&s[i].find("qiandao")==s[i].npos){
m--;
}
}
cout<<"Wo AK le"<<endl;
return 0;
}
L1-7
先把所有数存进数组里面。
然后就是利用
C
+
+
C++
C++自带的函数直接算出答案。
用
∗
m
i
n
_
e
l
e
m
e
n
t
*min\_element
∗min_element函数找出
v
e
c
t
o
r
vector
vector里面的最小值
m
i
n
min
min,
然后再用
c
o
u
n
t
count
count函数计算
m
i
n
min
min的出现次数即可。
最大值同理。
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
int n=read();rp(i,1,n) a[i]=read();
int min=*min_element(a+1,a+1+n);
cout<<min<<" "<<count(a+1,a+1+n,min)<<endl;
int max=*max_element(a+1,a+1+n);
cout<<max<<" "<<count(a+1,a+1+n,max)<<endl;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
// freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
L1-8
直接按照题意模拟就行了。
注意一下
a
1
=
=
0
a_{1}==0
a1==0或者
a
2
=
=
0
a_{2}==0
a2==0的情况。
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
int a1=read(),a2=read(),n=read();
vector<int> res;
int cur0=0,cur1=1;
res.push_back(a1);
res.push_back(a2);
while(res.size()<n){
int num=res[cur0]*res[cur1];
if(num==0){
res.push_back(0);
cur0++;
cur1++;
continue;
}
int temp=num;
vector<int> tt;
while(temp>0){
tt.push_back(temp%10);
temp/=10;
}
reverse(tt.begin(),tt.end());
for(auto val:tt) res.push_back(val);
cur0++;cur1++;
}
rp(i,0,n-1) cout<<res[i]<<(i==n-1?"\n":" ");
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
// freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
L2-1
用一个栈来维护筐,一个
v
e
c
t
o
r
vector
vector维护流水线。
至于每次过程可以直接用
s
t
r
i
n
g
string
string维护轨道,直接调用自带的
e
r
a
s
e
erase
erase函数每次删除第一个字符就行了。
快的方法就可以用一个
d
e
q
u
e
deque
deque来维护轨道,每次操作直接调用
p
o
p
_
f
r
o
n
t
pop\_front
pop_front函数和
f
r
o
n
t
front
front函数即可。
trick:注意如果轨道为空时,按对应按钮时不会强制执行0号键
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
deque<char> s[107];
void solve(){
int N=read(),M=read(),S=read();
rp(i,1,N){
rp(j,1,M){
char ch;scanf("%c",&ch);
s[i].push_back(ch);
}
getchar();
}
// rp(i,1,N){
// for(auto val:s[i]) cout<<val;
// cout<<endl;
// }
stack<char> ss;
vector<char> res;
int op;
while(~scanf("%d",&op)){
if(op==-1) break;
if(op==0){
if(ss.size()!=0){
res.push_back(ss.top());ss.pop();
}
}
else{
if(s[op].size()==0) continue;
if(ss.size()>=S){
res.push_back(ss.top());
ss.pop();
}
ss.push(s[op].front());
s[op].pop_front();
}
}
for(auto val:res) cout<<val;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
// freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
L2-2
求树的直径,直接
d
f
s
dfs
dfs先搜索出最小的最远端点
p
o
s
pos
pos。
然后再以
p
o
s
pos
pos端点进行
d
f
s
dfs
dfs搜索,同时用一个
v
e
c
t
o
r
vector
vector维护答案就行了。
注意比较字典序时,需要找到第一个不相等的数,再根据题意判断大于还是小于符合条件。
代码不给了,也比较好写。
L2-3
学长说可以
m
a
p
map
map维护
v
e
c
t
o
r
vector
vector过。
但是我的这个做法超时了,因此改成了
h
a
s
h
hash
hash才过。
关于哈希算法不懂的可以参考我的这篇博客:戳我。
不过重载比较函数(字典序)时出了点
b
u
g
bug
bug,赛后发现了(比赛时第二次出现这个错误了)。
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define sc(x) scanf("%d",&x);
#define scl(x) scanf("%lld",&x);
#define rp(i,s,t) for(int i=(s);i<=(t);i++)
#define RP(i,s,t) for(int i=(s);i>=(t);i--)
#define outval(x) printf("%d\n",x);
#define outval2(x,y) printf("%d %d\n",x,y);
#define outval3(x,y,z) printf("%d %d %d\n",x,y,z);
#define pY puts("Yes")
#define pN puts("No")
using namespace std;
const int N = 1e5+7;
const int INF = 0x3f3f3f3f;
const ll mod1 = 1e9+7;
const ll p = 12582917;
map<ll,int> mp;
int n,m;
bool cmp(vector<ll> a,vector<ll> b){
if(mp[a[m]]!=mp[b[m]]) return mp[a[m]]>mp[b[m]];
else{
rp(i,0,m-1){
if(a[i]<b[i]) return 1;
else if(a[i]==b[i]) continue;
else return 0;
}
}
}
int main(){
sc(n);sc(m);
vector<vector<ll> >res;
rp(i,1,n){
vector<ll> temp;
rp(j,0,m-1){
ll x;scl(x);
temp.push_back(x);
}
ll res1=0;
rp(j,0,m-1) res1=(res1*p%mod1+temp[j])%mod1;
temp.push_back(res1);
if(mp.find(res1)==mp.end()) res.push_back(temp);
mp[res1]++;
}
sort(res.begin(),res.end(),cmp);
cout<<res.size()<<endl;
for(auto val:res){
int len=val.size();
ll res1=0;
rp(j,0,m-1) res1=(res1*p+val[j])%mod1;
cout<<mp[res1];
rp(j,0,m-1) cout<<" "<<val[j];
cout<<endl;
}
return 0;
}
L2-4
题意有点恶心,不过理解后就是一道
n
t
nt
nt题。
算是
L
2
L2
L2中最简单的题,直接按照题意模拟就行了。
代码就不放了,不想再写一遍了。。。
L3-1
经典最短路题,算是比较套路的题目了。
题目要求我们在一个点换了旅游金之后就只能使用旅游金支付,其实就是从这个点到终点花费的最小的旅游金数目。
而我们需要先到这个点,在前面我们只能支付现金,即从起始点到当前点花费的最小现金数目。
所以题目被转换成了从1到i花费的最小现金数+从i到n花费的最小旅游金的数目/汇率(上取整)。
从1到i花费的最小现金数我们可以直接建边(边权为现金),然后跑最短路即可。
而从从i到n花费的最小旅游金的数目相对没这么好求了,
不过也算是最短路的经典问题。
我们可以直接建反图(边权为旅游金),最短路维护的是反图中n->i的花费的最小旅游金数目,即对应原图中i->n花费的最小旅游金的数目。
关于反向建边不懂的话可以参考这篇blog。
对于最短路,我们需要用Dijkstra+堆优化维护,
保证时间复杂度为O(nlogn)。
这样我们对于每次查询直接暴力只能拿22分。
然后我们考虑优化。
我们发现每次我们只会修改一个地方的汇率,那么我们就可以用一个map来维护所有点产生的答案以及其个数,一个set来记录所有点产生的答案,每次修改最多会删除一个点(set中的erase函数时间复杂度为logn),每次查询最小值是O(1)的。
总的时间复杂度就是O(nlogn)。
不过这个题会卡常,注意把cin和cout改成printf和scanf就行了。
trick:
1.会出现自环
2.会出现重边
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define sc(x) scanf("%d",&x);
#define scl(x) scanf("%lld",&x);
#define rp(i,s,t) for(register int i=(s);i<=(t);i++)
#define RP(i,s,t) for(register int i=(s);i>=(t);i--)
#define outval(x) printf("%d\n",x);
#define outval2(x,y) printf("%d %d\n",x,y);
#define outval3(x,y,z) printf("%d %d %d\n",x,y,z);
#define pY puts("Yes")
#define pN puts("No")
#define p_b push_back
#define m_p make_pair
#define pii pair<int,int>
#define pil pair<int,ll>
using namespace std;
const int N = 2e5+7;
const int INF = 0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
struct edge{int u,v;ll c,d;}p[N];
vector<pil> G[N];
ll a[N];
ll dis1[N],dis2[N];
int vis[N];
struct node{
int p;
ll w;
friend bool operator < (node a,node b){
return a.w>b.w;
}
};
set<ll> ss;
map<ll,int> mp;
int n,m,q;
void Dijkstra1(){
rp(i,1,n) dis1[i]=LINF,vis[i]=0;
dis1[1]=0;
priority_queue<node> q;
q.push(node{1,dis1[1]});
while(!q.empty()){
node t=q.top();q.pop();
int u=t.p;vis[u]=1;
ll w=t.w;
// cout<<u<<" "<<w<<endl;
for(auto val:G[u]){
int v=val.first;
if(!vis[v]&&dis1[v]>val.second+w){
dis1[v]=val.second+w;
// cout<<v<<" "<<dis1[v]<<endl;
q.push(node{v,dis1[v]});
}
}
}
}
void Dijkstra2(){
rp(i,1,n) dis2[i]=LINF,vis[i]=0;
dis2[n]=0;
priority_queue<node> q;
q.push(node{n,dis2[n]});
while(!q.empty()){
node t=q.top();q.pop();
int u=t.p;vis[u]=1;
ll w=t.w;
for(auto val:G[u]){
int v=val.first;
if(!vis[v]&&dis2[v]>val.second+w){
dis2[v]=val.second+w;
q.push(node{v,dis2[v]});
}
}
}
}
int main(){
// freopen("in.txt","r",stdin);
sc(n);sc(m);sc(q);
rp(i,1,m){
sc(p[i].u);
sc(p[i].v);
scl(p[i].c);
scl(p[i].d);
}
rp(i,1,n) scl(a[i]);
rp(i,1,m){
if(p[i].u==p[i].v) continue;
G[p[i].u].push_back(make_pair(p[i].v,p[i].c));
}
Dijkstra1();
rp(i,1,n) G[i].clear();
rp(i,1,m){
if(p[i].u==p[i].v) continue;
G[p[i].v].push_back(make_pair(p[i].u,p[i].d));
}
Dijkstra2();
// cout<<"test1"<<endl;
// rp(i,1,n) cout<<i<<" "<<dis1[i]<<endl;
// cout<<"test2"<<endl;
// rp(i,1,n) cout<<i<<" "<<dis2[i]<<endl;
int x;ll aa;
sc(x);scl(aa);a[x]=aa;
rp(i,1,n){
if(dis1[i]==LINF||dis2[i]==LINF) continue;
ll ans=dis1[i]+1ll*(dis2[i]+a[i]-1)/a[i];
ss.insert(ans);
mp[ans]++;
}
// for(auto val:ss) cout<<"debug val: "<<val<<endl;
printf("%lld\n",*ss.begin());
q--;
while(q--){
sc(x);scl(aa);
if(dis1[x]!=LINF&&dis2[x]!=LINF){
ll ans=dis1[x]+1ll*(dis2[x]+a[x]-1)/a[x];
mp[ans]--;
if(mp[ans]==0) ss.erase(ans);
a[x]=aa;
ans=dis1[x]+1ll*(dis2[x]+a[x]-1)/a[x];
mp[ans]++;
ss.insert(ans);
}
printf("%lld\n",*ss.begin());
}
return 0;
}
L3-2
数据很水,直接dfs暴力拿满。
直接贪心取最长串+哈希的话能拿26分,不过是明显的错误做法。
h
a
c
k
hack
hack数据(学长提供的):
121212
1212
121
正解应该是
a
c
ac
ac自动机+
d
p
dp
dp。
L3-3
没有做,不过听说是一道cf上的莫比乌斯反演题改编的。