暑假终于结束了,打了很多比赛还有很多题没有补,慢慢补一下,包括河南萌新联赛和杭电多校部分题目,希望能打上网络赛和邀请赛什么的,区域赛感觉自己太菜了没机会呜呜呜
咳咳,先补题吧
很恶心的一道题,卡常非常严重,map遍历不能使用迭代器,只能用auto,其他的就是数据结构疯狂开了,在输入a[i]时,mp[a[i]]=1时直接压入赛时难度的vector,然后map配合优先队列算出总难度,对比即可,因为两个难度vector中数的集合一定是相同的,所以无需管余下的数,这里一种写法,定义优先队列时直接加上定义的cmp,可以优化时间
下次先看大家发的反馈,要是卡常,提前考虑优化,少罚时
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL>PII;
const int N=1e6+10;
LL t,n,m;
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
vector<LL>a(m+1);
vector<LL>vv;//赛时榜
vector<LL>v;
unordered_map<LL,LL>mp;
auto cmp=[](PII A,PII B)
{
if(A.first!=B.first)return A.first<B.first;
else return A.second>B.second;
};
priority_queue<PII,vector<PII>,decltype(cmp)>q(cmp);
for(int i=0;i<m;i++)
{
scanf("%lld",&a[i]);
mp[a[i]]++;
if(mp[a[i]]==1)vv.push_back(a[i]);
}
for(auto& p:mp)q.push({p.second, p.first});
while(!q.empty())
{
LL a;
a=q.top().second;
v.push_back(a);
q.pop();
}
LL cnt=0;
LL s=min(v.size(),vv.size());
for(int i=0;i<s;i++)if(vv[i]!=v[i])cnt++;
printf("%lld\n",cnt);
}
return 0;
}
这道题首先明确题意:
- 是回文串
- 子串中存在括号串
先找出回文子串,dp模板,
for(int i=n;i>=1;i--)
{
for(int j=i;j<=n;j++)
{
if(s[i]==s[j])dp[i][j]=(i+1<j)?dp[i+1][j-1]:true;
if(dp[i][j])return true;
}
}
当找到子串时,我们考虑第二部分,判断是否含有括号串,简单一点,直接找有没有()因为只要求有一个即可,无需考虑更长的,有()则是,无则不是,为了加快速度,我们预处理每个()开始的位置,然后在dp中进行二分,判断i~j中是否含有()
这道题对空间要求很高,要注意判断,只能在dp中直接判断,不能使用vector记录,否则MLE
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
const int N=1e4+10;
string s;
int main()
{
cin>>s;
int n=s.size();
s=" "+s;
vector<int>kl(n+2,0);
vector<int>kr(n+2,0);
for(int i=1;i<=n;i++)
{
if(s[i]=='(')kl[i]=kl[i-1]+1;
else kl[i]=kl[i-1];
if(s[i]==')')kr[i]=kr[i-1]+1;
else kr[i]=kr[i-1];
}
vector<vector<bool>>dp(n+2,vector<bool>(n+2,false));
int ans=0;
vector<int>v;
for(int i=1;i<=n;i++)if(s[i]=='('&&s[i+1]==')')v.push_back(i);
int m=v.size();//括号总数
for(int i=n;i>=1;i--)
{
for(int j=i;j<=n;j++)
{
if(s[i]==s[j])dp[i][j]=(i+1<j)?dp[i+1][j-1]:true;
if(dp[i][j]&&i!=j)
{
if(m==0)continue;
int L=i,R=j-1;
int l=0,r=m-1;
bool f=0;
while(l<=r)
{
int mid=(l+r)/2;
if(v[mid]>=L&&v[mid]<=R)
{
f=1;
break;
}
else if(v[mid]<L)l=mid+1;
else r=mid-1;
}
if(f)ans++;
}
}
}
cout<<ans;
return 0;
}
然后是补了一道1001的题,这种九百多个人过的题应该要写出来的,唉
首先从直觉来看,最高点一定需要传送门,因为没有点可以直接走到最高点,提取这个性质进行扩展,
所有平面地图上高度的极点一定都需要传送门,且只有这些点需要,这样,建立的地图及建立传送门所需要的钱已经明确,
而后就是将这些点相连,即最小生成树,我们观察传送时的代价,即使高度值相差只有1,919810也比x,y均相差为100的代价要大,
故只需要考虑高度即可,易得从低到高相连就是最小生成树,
也可使用prim证明,每次选择集合外距离集合最近的点一定是集合外最低点
这里小细节,起点一定要进入小根堆,然后判断时跳过,由于起点传送门不要钱,传送门总价格就是队内元素数量-1乘价格
AC代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef long long LL;
typedef pair<LL,pair<LL,LL> >PII;//高度,坐标
const int N=100+10;
const int mod=1e9+7;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
LL g[N][N];
LL t,n,m;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--)
{
LL ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)cin>>g[i][j];
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({g[1][1],{1,1}});
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1&&j==1)continue;
int f=1;
for(int k=0;k<4;k++)
{
int x=i+dx[k],y=j+dy[k];
if(x<1||x>n||y<1||y>m)continue;
if(g[x][y]>g[i][j])
{
f=0;
break;
}
}
if(f==1)q.push({g[i][j],{i,j}});
}
}
ans+=(q.size()-1)*17179869184;
PII z=q.top();
q.pop();//起点(初始化不能使用auto,否则默认为列表类型)
while(!q.empty())
{
auto t=q.top();
q.pop();
ans+=114*abs(t.se.fi-z.se.fi)+5141*abs(t.se.se-z.se.se)+919810*abs(t.fi-z.fi);
z=t;
}
cout<<ans<<endl;
}
return 0;
}