codeforces round 1043(div3) 补题
状态不太好,打得非常唐
补一下题吧
Problem - B - Codeforces
题意:给一个n,n为两个数x、y的和,其中y = x*(10^k),求出所有符合条件的x
改一下式子,n = x*(1+10^k)
枚举k就可以了
ll n;
void solve()
{cin>>n;string s = to_string(n);int len = s.size()-1;s = " "+s;ll ans=1;vector<ll> anss;for(int i=1;i<=len;i++){ans*=10;if(n%(ans+1)==0){anss.pb(n/(ans+1));}}cout<<anss.size()<<endl;if(anss.size()==0)return ;sort(anss.begin(),anss.end());for(auto it : anss){cout<<it<<' ';}cout<<endl;
}
Problem - C2 - Codeforces
题意: 每次交易可以买3^x个物品,花费3^(x+1) + x*3^(x-1)块钱,限制为不超过k次交易,精确购买n个物品,求出最少花费,无法购买则输出-1.
问题1:有解性。将物品总数按照三进制拆分,此时每一位数字的和一定是最小方案,如果k达不到这个最小方案那么就是无解的。
问题2:最小花费。将费用公式化简可得:f(x) = 3^(x-1)*(9+x)。随着x的递增,花费增加得越快,推算一下就有f(x)>3*f(x-1)。所以如果当前的方案还达不到k次,那么将高位的一次交易拆成三个较低位的交易,交易次数增加2,枚举即可。
while (t--) {long long n, k;cin >> n >> k;vector <long long> tr;long long min_k = 0;while (n) {tr.push_back(n % 3);min_k += n % 3;n /= 3;}if (min_k > k) {cout << -1 << '\n';continue;}k -= min_k;k /= 2;for (int i = (int)tr.size() - 1; i >= 1; --i) {if (tr[i] <= k) {tr[i - 1] += 3 * tr[i];k -= tr[i];tr[i] = 0;} else {tr[i - 1] += k * 3;tr[i] -= k;break;}}long long an = 0;for (int i = (int)tr.size() - 1; i >= 0; --i)an += cost[i] * tr[i];cout << an << '\n';}
Problem - E - Codeforces
题意:小A和小B有两副牌a_1~n、b_1~m,对于每次操作,分别限制两人的可选择的牌数x、y以及两人一共应的牌数z,使得两人的牌面数值总和最大。
模拟一下发现需要先从大到小排个序,因为每次取的是两边剩下牌面的最大值。
由于q很大,每次询问的时候再找会很费时间,不如先把0到n+m的所有情况先求出来,记录一共取i个牌时,a和b分别要拿多少张。
然后每次查询的时候O(1)输出前缀和就好了,对于要拿的数小于应该拿的,就让另一边多拿即可
ll n,m,q;
ll a[N],b[N],sa[N],sb[N],xa[N<<1],xb[N<<1];
void solve()
{cin>>n>>m>>q;for(int i=1;i<=n;i++){cin>>a[i];}sort(a+1,a+n+1,cmp1);for(int i=1;i<=n;i++){sa[i] = sa[i-1]+a[i];}for(int i=1;i<=m;i++){cin>>b[i];}sort(b+1,b+m+1,cmp1);for(int i=1;i<=m;i++){sb[i] = sb[i-1]+b[i];}int pa= 0,pb= 0;for(int i=1;i<=n+m;i++){if(pb == m || pa<n && a[pa+1]>=b[pb+1]){pa++;}else{pb++;}xa[i] = pa;xb[i] = pb;}xa[m+n] = n;xb[m+n] = m;while(q--){ll x,y,z;cin>>x>>y>>z;ll ans = 0;if(x>=xa[z] && y>=xb[z]){cout<<sa[xa[z]]+sb[xb[z]]<<endl;}else if(y<xb[z]){cout<<sb[y]+sa[z-y]<<endl;}else if(x<xa[z]){cout<<sa[x]+sb[z-x]<<endl;}}
}
Problem - F - Codeforces
题意:给一个简单无向图,每个边都有编号,找到所有1能走到n的路径中的必经边。然后是q次查询,每次查询给定一个位置x,求距离其最近的必经路的编号,若距离相同则取编号更小的。
问题1:求必经路。手玩一下样例发现,必经路是图中的割边,若不是割边那么根据连通性,肯定存在其他路能到达n。
问题2:求割边。这里直接用了个tarjan的板子,把所有的割边放进一个集合内。然后回到问题1,从1到n跑一遍bfs,然后把途中的路径记录下来,找到属于割边集的提取出来,这样就找完了必经路。
问题3:求解。既然求距离最小的,我们只需要让这个边某个端点最快达到x即可。用多源最短路径预处理,每次查询直接输出答案。总时间复杂度为O(m+m+nlog(m)+q)。
int n,m,tot,q;
map<PII,int> hs;
PII hsp[N];
vector<int>v[N];
set<PII> bri,brii;
int visd[N];
struct node
{int st,ed,id;bool operator < (const node & p) const{return st>p.st || st == p.st && ed>p.ed;}
};
int low[N], dfn[N], idx=0;
bool isbridge[N];
int cnt_bridge;
int father[N];
void dfs(int u, int fa)
{father[u] = fa;low[u] = dfn[u] = ++idx;for (auto t : v[u]){if (!dfn[t]){dfs(t, u);low[u] = min(low[u], low[t]);if (low[t] > dfn[u]){bri.insert({min(u,t),max(u,t)});isbridge[t] = 1;++cnt_bridge;}}else if (t != fa){low[u] = min(low[u], dfn[t]);}}
}
void bfs()
{brii.clear();vector<bool> tv(n+5,0);vector<int>pre(n+5,0);queue<int>q;q.push(1);while(q.size()){int now = q.front();q.pop();if(now == n){break;}if(tv[now]) continue;tv[now] = 1;for(auto t : v[now]){if(!tv[t]){pre[t] = now;q.push(t);}}}int now = n;while(pre[now]!=0){if(bri.count({min(now,pre[now]),max(now,pre[now])}) >0){brii.insert({min(now,pre[now]),max(now,pre[now])});}now = pre[now];}
}
void solve()
{cnt_bridge = 0;idx = 0;cin>>n>>m;for(int i=1; i<=n; i++){isbridge[i] = 0;low[i] = 0;dfn[i] = 0;father[i] = 0;v[i].clear();}bri.clear();for(int i=1; i<=m; i++){int x,y;cin>>x>>y;v[x].pb(y);v[y].pb(x);hs[ {min(x,y),max(x,y)}] = i;hsp[i] = {min(x,y),max(x,y)};}dfs(1,0);bfs();priority_queue<node> pq;bool f = 0;if(brii.size() == 0) f = 1;for(auto it : brii){pq.push((node){0,hs[ {it.fi,it.se}],it.fi});pq.push((node){0,hs[ {it.fi,it.se}],it.se});}vector<int> ans(n+5,0);while(pq.size()){node now = pq.top();pq.pop();if(ans[now.id]) continue;ans[now.id] = now.ed;for(auto t : v[now.id]){if(!ans[t]){pq.push((node){now.st+1,now.ed,t});}}}cin>>q;while(q--){int x;cin>>x;if(f){cout<<-1<<' ';continue;}cout<<ans[x]<<' ';}cout<<endl;
}
加训加训加训!被队友压力死了()