思路:
啥也不说了,一道让我气到吐血的题,记录一下精神不太好的发病期。
代码:
#include <bits/stdc++.h>
#define ll long long
const int maxn = 2e5 + 10;
using namespace std;
int n;
ll m;
ll a[maxn],b[maxn];
ll res,ans;
map<ll,ll>s;
int main()
{
cin >> n >> m;
int t=0;
for (int i = 1; i <= n; i++)
{
cin >> b[i];
res += b[i];//总和
}
sort(b+ 1, b + 1 + n);
ll sum=b[n];//记录最大值
ans=b[n];//记录连续和
//从后往前遍历,s[i]记录数i目前能减去的数和
for(int i=n-1;i>=1;i--)
{
if(b[i]==b[i+1])
{
ans+=b[i];
s[b[i]]=ans;
sum=max(sum,ans);
}
else if((b[i]+1)%m==b[i+1])
{
s[b[i+1]]=ans;
ans+=b[i];
sum=max(sum,ans);
}
else
{
s[b[i+1]]=ans;
sum=max(sum,ans);
ans=b[i];
}
}
s[b[1]]=ans;//记得更新第一个数
//更新s[i],(i+1)%m的范围在[0,m)的情况
for(int i=n;i>=1;i--)
{
if(b[i]>=(m)&&b[i+1]!=b[i])
{
if(s[(b[i]+1)%m])
{
s[b[i]]+=s[(b[i]+1)%m];
sum=max(sum,s[b[i]]);
}
}
}
//需要特判若出现m-1的数取模时是否要加上s[0]
//记录与0连续的区间,与m-1连续的区间
//若区间不重合,则加上
int l0=-1,r0=-1,lm=-1,rm=-1;
if(b[0]==0)l0=1;
for(int i=1;i<=n-1;i++)if(b[1]==0&&(b[i]+1<b[i+1])){r0=i;break;}
for(int i=n;i>=1;i--)
{
if(b[i]==m-1)rm=max(rm,i);
else if(rm!=-1&&(b[i]+1<b[i+1])){lm=i+1;break;}
}
//区间不重合,把与m-1的区间最左边的数加上s[0]
if(l0!=-1&&lm!=-1&&r0<lm)
{
s[b[lm]]+=s[0];
sum=max(sum,s[b[lm]]);
}
for(auto x:s)
{
// cout<<x.first<<":"<<x.second<<endl;
sum=max(sum,x.second);
}
//cout<<"res:"<<res<<" ans:"<<ans<<endl;
cout << res - sum << endl;
system("pause");
return 0;
}
E - Crystal Switches
思路:很妙的方法,通过将有按钮的节点连接它的两个01图。
参考:mibamiba_
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+10;
struct node
{
int to,d;//到达点以及权值
};
//优先队列排序
struct cmp1
{
bool operator()(node u,node v)
{
return u.d>v.d;
}
};
priority_queue<node,vector<node>,cmp1>q;
bool vh[maxn];//记录某点是否走过
vector<node>w[maxn];
int n,m,k,u,v,x,dis[maxn];
void dijkstra()
{
q.push(node{1,0});
memset(dis,127,sizeof(dis));//初始化设置为正无穷
dis[1]=0;
while(!q.empty())
{
node p=q.top();//队头
q.pop();//出队
if(vh[p.to])continue;//判断该点是否经过
vh[p.to]=true;
for(int i=0;i<w[p.to].size();i++)//遍历通过该点到达的所有点
{
int ls=w[p.to][i].to,ns=w[p.to][i].d;//到达的节点以及权值
if(dis[ls]>dis[p.to]+ns)//更新最短路
{
dis[ls]=dis[p.to]+ns;
q.push(node{ls,dis[ls]});//将新节点以及最短路放进去
}
}
}
if(min(dis[n],dis[n+n])>1e9)cout<<"-1"<<endl;
else cout<<min(dis[n],dis[n+n])<<endl;
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>x;
//w[u]表示1图,w[u+n]表示0图
if(x)w[u].push_back(node{v,1}),w[v].push_back(node{u,1});
else w[u+n].push_back(node{v+n,1}),w[v+n].push_back(node{u+n,1});
}
for(int i=1;i<=k;i++)
{
cin>>x;
//有按钮的节点可通过连接的所有点,连接x的0,1图
w[x].push_back(node{x+n,0});
w[x+n].push_back(node{x,0});
}
dijkstra();
//system("pause");
return 0;
}