获得姿势:要构造数,想到用二进制构造。
一直向最左路构造,最左路的和是(2^k)-1,加入给定n,那么被减去的数字是d = (2^k)-1-n. 当我要减去一个数字时,从上往下走,对于总和相当于减去二倍的数字,所以要d/2.但前提是保证d为偶数。即为奇数时d = (2^k)-n.因为减去一个数,总是损失二倍的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; int main() { int t,kase = 0; scanf("%d",&t); while(t--) { ll n,k; scanf("%I64d %I64d",&n,&k); printf("Case #%d: ",++kase); ll sum = (1LL<<k)-1; // - 和 + 优先级比<<高 int flag = 0; sum -= n; if(sum%2) { sum += 1; flag = 1; } sum /= 2; for(int i = 0; i<k-1; i++) { printf("%I64d ",1LL<<i); if(sum&(1LL<<i)) printf("- "); else printf("+ "); } if(flag) printf("%I64d + ",(1LL<<(k-1))+1); else printf("%I64d + ",1LL<<(k-1)); } return 0; }
先把自己的SB代码保存下来,昨天WA了十五发,最近应该不会再看了。QAQ
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #include <vector> using namespace std; typedef long long ll; const int maxn = 3e6+5; ll d1[maxn],d2[maxn]; bool done[maxn]; const ll INF = 0x3f3f3f3f3f3f3f3fLL; struct edge { int to; ll cost; friend bool operator < (edge A,edge B) { return A.cost>B.cost; } }; vector<edge> g[maxn]; vector<int> dd; void add(int u,int v,ll w) { g[u].push_back((edge){v,w}); // g[v].push_back((edge){u,w}); } void dijkstra(int s,int e,ll d[]) { priority_queue<edge> q; memset(done,false,sizeof(done)); for(int i = 1; i<=maxn; i++) d[i] = INF; d[s] = 0; q.push((edge){s,0}); while(!q.empty()) { edge cur = q.top(); q.pop(); int v = cur.to; if(done[v]) continue; done[v] = true; for(int i = 0; i<g[v].size(); i++) { cur = g[v][i]; if(d[cur.to]>d[v]+cur.cost) { d[cur.to] = d[v]+cur.cost; q.push((edge){cur.to,d[cur.to]}); } } } } int main() { int t,kase = 0; scanf("%d",&t); while(t--) { int n,m; ll tt; int s,x; int in,out; cin>>n>>m; for(int i = 1; i<=m; i++) { scanf("%I64d %d",&tt,&s); in = n+i; out = n+m+i; add(in,out,tt); // add(out,in,tt); for(int j = 1; j<=s; j++) { scanf("%d",&x); add(x,in,0); add(out,x,0); } } dijkstra(1,n,d1); dijkstra(n,1,d2); ll minn = INF; printf("Case #%d: ",++kase); for(int i = 1; i<=n; i++) minn = min(minn,max(d1[i],d2[i])); if(minn == INF) { printf("Evil John "); continue; } printf("%I64d ",minn); for(int i = 1; i<=n; i++) if(max(d1[i],d2[i])==minn) { dd.push_back(i); } int first = 0; for(int i=0;i<dd.size();i++) { if(first==0) { printf("%d",dd[i]); first = 1; } else printf(" %d",dd[i]); } printf(" "); for(int i = 1; i<=maxn; i++) g[i].clear(); dd.clear(); } return 0; }
呀,最近自己有毒,不wa上十几发是不会过的,不对,wa了十几发也不一定过。
对边排序,对查询排序,并查集。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 1e5+5; const int maxn1 = 2e4+5; struct edge { int u,v,w; }; edge e[maxn]; int pre[maxn1]; int cnt[maxn1]; int n,m,qq; struct query { int k; int ans; int x; }; query q[5005]; void inin() { for(int i=1;i<=n;i++) { pre[i] = i; cnt[i] = 1; } } int find1(int x) { int r = x; while(r!=pre[r]) { r = pre[r]; } int i = x,j; while(pre[i]!=r) { j = pre[i]; pre[i] = r; i = j; } return r; } bool cmp1(edge A,edge B) { return A.w<B.w; } bool cmp2(query A,query B) { return A.x<B.x; } bool cmp3(query A,query B) { return A.k<B.k; } int main() { int t; cin>>t; while(t--) { memset(e,0,sizeof(e)); memset(q,0,sizeof(q)); cin>>n>>m>>qq; int u,v,w; for(int i=1;i<=m;i++) { scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w); } sort(e+1,e+m+1,cmp1); int x; for(int i=1;i<=qq;i++) { scanf("%d",&x); q[i].k = i; q[i].x = x; } sort(q+1,q+qq+1,cmp2); int index = 1; inin(); int fx = 0; int fy = 0; int ans = 0; for(int i=1;i<=qq;i++) //手残,加了个index<=m,导致后面的不更新了 { while(e[index].w<=q[i].x&&index<=m) { fx = find1(e[index].u); fy = find1(e[index].v); if(fx != fy) { pre[fx] = fy; ans -= (cnt[fx]*(cnt[fx]-1)); ans -= (cnt[fy]*(cnt[fy]-1)); cnt[fy] += cnt[fx]; ans += (cnt[fy]*(cnt[fy]-1)); } index++; }q[i].ans = ans; } sort(q+1,q+qq+1,cmp3); for(int i=1;i<=qq;i++) printf("%d ",q[i].ans); } return 0; }