签到。
暴力思路是三重枚举,可优化至两重枚举。
int n;
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n;
bool ok=false;
for(int i=0;3*i<=n && !ok;i++)
for(int j=0;3*i+5*j<=n && !ok;j++)
{
int k=n-3*i-5*j;
if(k % 7 == 0)
{
ok=true;
cout<<i<<‘ ‘<<j<<‘ ‘<<k/7<<endl;
}
}
if(!ok) puts("-1");
}
//system("pause");
return 0;
}
贪心。
\(k\)次操作,每次可选定一对元素\((a_i,a_j)\),使得其中一个增加\(c\),另一个减少\(c\),\(0 \le c \le a_i\)。
最小值最终一定为\(0\),最大值初值可设为序列中的最大值。
显然每次操作的\(c\)越大越好,于是\(c\)取除去最大值后序列中的前\(k\)大值即为最优。
const int N=2e5+10;
int a[N];
int n,k;
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>k;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n,greater<int>());
LL res=a[0];
for(int i=1;i<=k;i++) res+=a[i];
cout<<res<<endl;
}
//system("pause");
return 0;
}
若想\(d_i\)保持不变的点尽量多,从最短路树的根节点\(1\)开始任意选一个包含\(k\)条边的连通块即可,这样可使得\(k+1\)个点的\(d_i\)保持不变。
于是记录最短路树中的所有边的编号,保留出队的前\(k\)条边存入\(res\)数组中即可。
Dijkstra算法每个节点仅出队一次,出队顺序满足拓扑序,于是优先出队的前\(k\)条边一定是属于同一个连通块的。
const int N=1e5+10;
struct Node
{
int v;
LL dis;
int idx;
bool operator>(const Node &W) const
{
return dis > W.dis;
}
};
vector<Node> g[N];
LL dist[N];
bool vis[N];
int n,m,k;
vector<int> res;
void dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<Node, vector<Node>, greater<Node>> heap;
heap.push({1,0,0});
while (heap.size())
{
int t=heap.top().v, idx=heap.top().idx;
heap.pop();
if (vis[t]) continue;
vis[t] = true;
if(idx && res.size() < k) res.pb(idx);
for(int i=0;i<g[t].size();i++)
{
int j = g[t][i].v, w=g[t][i].dis, idx=g[t][i].idx;
if (dist[j] > dist[t] + w)
{
dist[j] = dist[t] + w;
heap.push({j, dist[j], idx});
}
}
}
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g[a].pb({b,c,i});
g[b].pb({a,c,i});
}
dijkstra();
cout<<res.size()<<endl;
for(auto &t : res)
cout<<t<<‘ ‘;
cout<<endl;
//system("pause");
return 0;
}
原文:https://www.cnblogs.com/fxh0707/p/14855049.html