当前位置: 首页 > news >正文

nflsoi 8.2 题解

C.#15563 ab串字典序 / AT_abc202_d aab aba baa

题意

请你求出由 AAAaBBBb 组成的长度为 A+BA+BA+B 的字符串中,按字典序排列后的第 KKK 个字符串。

1≤A,B≤301\le A,B\le 301A,B30

思路

最多有 2602^{60}260 种字符串,肯定不能一个一个枚举了。我们考虑在 1∼A+B1\sim A+B1A+B 位中填入恰当的 ab 使字典序恰为 KKK

dfs 决策一位填 a 还是填 b:我们发现填 b 会使字符串的字典序变大!

对于前面 t−1t-1t1 位全部相同,还有 A0A_0A0aB0B_0B0b 可以填。t∼A+Bt\sim A+BtA+B 位字符串 a (A0-1)×a (B0-1)×bb A0×a (B0-1)×b 这两个字符串,字典序会相差“A0−1A_0-1A01aB0B_0B0b 全排的不同方案数”。

因此填 b 升高那么多字典序,这个差值可以 dp 计数算出来:设 fi,jf_{i,j}fi,j 表示 iiiajjjb 全排的不同方案数,有转移:
fi,j←fi−1,j(i>0)fi,j←fi,j−1(j>0)\begin{matrix} f_{i,j}\leftarrow f_{i-1,j}(i>0)\\ f_{i,j}\leftarrow f_{i,j-1}(j>0) \end{matrix}fi,jfi1,j(i>0)fi,jfi,j1(j>0)

初始化 f0,0=1f_{0,0}=1f0,0=1

如果出现 a 或者 b 用完的情况,后面全部填其他字母即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=33;
ll a,b,t;
string lh[2][N];
ll f[N][N];
string dfs(ll rest,ll tota,ll totb)
{if(tota==0)return lh[1][totb];if(totb==0)return lh[0][tota];if(rest>f[tota-1][totb])return 'b'+dfs(rest-f[tota-1][totb],tota,totb-1);return 'a'+dfs(rest,tota-1,totb);//放b可以升高字典序 
}
int main()
{scanf("%lld%lld%lld",&a,&b,&t);f[0][0]=1;for(int i=0;i<=a;i++){for(int j=0;j<=b;j++){if(i)f[i][j]+=f[i-1][j];if(j)f[i][j]+=f[i][j-1];}}for(int i=1;i<=a;i++)lh[0][i]=lh[0][i-1]+'a';for(int i=1;i<=b;i++)lh[1][i]=lh[1][i-1]+'b';cout<<dfs(t,a,b);return 0;
}

D.#15528 复合函数查询 / AT_abc196_e Filters

题目传送门

感觉这题挺无脑的,是计算答案的上下界,然后搞一个加法的 tagtagtag,最后对询问的 x+tagx+tagx+tag 然后限制在上下界之间——简洁优美!

机房好多人做出来,好厉害。不过我暴力都有 85pts 的。。。

E.#4940 数对数字和 / AT_arc158_c All Pair Digit Sums

题意

对于正整数 xxx,记其各位数字之和为 f(x)f(x)f(x)。例如,f(158)=1+5+8=14f(158) = 1 + 5 + 8 = 14f(158)=1+5+8=14f(2023)=2+0+2+3=7f(2023) = 2 + 0 + 2 + 3 = 7f(2023)=2+0+2+3=7f(1)=1f(1) = 1f(1)=1

给定一个正整数序列 a=(a1,a2,…,aN)a = (a_1, a_2,\ldots, a_N)a=(a1,a2,,aN),请计算 ∑i=1N∑j=1Nf(ai+aj)\displaystyle\sum_{i=1}^N\sum_{j=1}^N f(a_i + a_j)i=1Nj=1Nf(ai+aj) 的值。

1≤N≤2×1051 \leq N \leq 2 \times 10^51N2×1051≤ai<10151 \leq a_i < 10^{15}1ai<1015

思路

感觉没法从 O(n2)O(n^2)O(n2) 暴力去优化,数字和和数字本身没什么特别的关联。于是考虑把 ai+aja_i+a_jai+aj 拆开。

根据小学奥数知识,如果两个数加法过程中,没有发生进位,结果的数字和就是两数数字和相加。否则每进一次位数字和就 −9-99

比如 58+4758+4758+478+78+78+7 进一次位,1+5+41+5+41+5+4 进一次位;f(105)=6=f(58)+f(47)−2×9f(105)=6=f(58)+f(47)-2\times 9f(105)=6=f(58)+f(47)2×9

那么答案变成:
∑i=1N∑j=1Nf(ai)+f(aj)−9z(ai,aj)\sum_{i=1}^N\sum_{j=1}^N f(a_i)+f(a_j)-9z(a_i,a_j)i=1Nj=1Nf(ai)+f(aj)9z(ai,aj)

=2n∑i=1nf(ai)−9∑i=1N∑j=1Nz(ai,aj)=2n\sum_{i=1}^n f(a_i)-9\sum_{i=1}^N\sum_{j=1}^N z(a_i,a_j)=2ni=1nf(ai)9i=1Nj=1Nz(ai,aj)

其中 z(x,y)z(x,y)z(x,y) 表示 x+yx+yx+y 过程中发生进位的次数。

减号左边 O(15n)O(15n)O(15n) 内随便算,问题还是在进位次数怎么算。

  • 两个 nnn 位数相加,最多发生 nnn 次进位;
  • 1≤ai<10151 \leq a_i < 10^{15}1ai<1015

aia_iai 再大顶天就 151515 位,我们对于所有数对我们可以分别考虑 1∼151\sim15115 位上是否发生进位。

如果我们对每个数按位拆开,不仅还是 O(n2)O(n^2)O(n2),而且还要考虑低位会不会进个 111 过来。

对于枚举的第 ttt 位,我们不妨记录每个数的末 ttt 位:记 bt,ib_{t,i}bt,i 表示 aia_iai 的末 ttt 位,存在 aja_jajaia_iai 相加可以在 ttt 进位,当且仅当 bt,j+bt,i≥10t+1b_{t,j}+b_{t,i}\ge 10^{t+1}bt,j+bt,i10t+1,即 jjj 要满足 bt,j≥10t+1−bt,ib_{t,j}\ge 10^{t+1}-b_{t,i}bt,j10t+1bt,i。我们对 btb_tbt 数组排序,容易用二分 lower_bound 计算合法的 jjj 的个数。

ans=ans*2*n;
ll ws=1;
for(int t=1;t<=15;t++)
{ws*=10;//10^{t+1}sort(b[t]+1,b[t]+n+1);for(int i=1;i<=n;i++){ll minus=n-(lower_bound(b[t]+1,b[t]+n+1,ws-b[t][i])-b[t])+1;//查大于等于10^{t+1}-b[t][i]的个数minusans-=9*minus;//ai+aj过程中第t为进位次数 }
}

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2e5+9;
ll n,a[N];
ll b[17][N];
ll cal(ll x)
{ll ret=0;while(x){ret+=x%10;x/=10;}return ret;
}
int main()
{scanf("%lld",&n);ll ans=0;for(int i=1;i<=n;i++){scanf("%lld",&a[i]);ans+=cal(a[i]);ll x=a[i],ws=1;for(int t=1;t<=15;t++){ws*=10;b[t][i]=x%ws;}}ans=ans*2*n;ll ws=1;for(int t=1;t<=15;t++){ws*=10;sort(b[t]+1,b[t]+n+1);for(int i=1;i<=n;i++){ll minus=n-(lower_bound(b[t]+1,b[t]+n+1,ws-b[t][i])-b[t])+1;//查大于等于10^{t+1}-b[t][i]的个数,b[j]单调 ans-=9*minus;//ai+aj过程中第t为进位次数 }}printf("%lld",ans);return 0;
}

F.#4548 树上游戏 / 洛谷 P10641 BZOJ3252 攻略

题意

给定一个有 nnn 个结点的树,树有点权且点权为正整数。现选取 kkk 条从根结点出发到叶子结点的简单路径,求这些路径的并集上所有结点的点权之和的最大值。

1≤n≤2×1051\leq n\leq 2\times 10^51n2×1051≤wi≤231−11\leq w_i\leq 2^{31}-11wi2311

思路

这就很树剖啊。

我们定义重儿子为链长更长的,然后把树给剖开成一条条链——因为走过的贡献不重复算。这样剖肯定能把树剖完。

然后我们把所有链长搞下来从大到小排序,取前 kkk 大即可。

多测记得清空。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+9;
int T,n,k;
ll a[N];
vector<int>G[N];
bool nolt[N];
int big[N];
ll lng[N];
void dfs(ll u,ll fa)//长剖 
{for(auto v:G[u]){if(v==fa)continue;dfs(v,u);if(lng[v]>lng[big[u]])big[u]=v;}lng[u]=lng[big[u]]+a[u];
}
int tot;
ll b[N];
bool cmp(ll x,ll y)
{return x>y;
}
void clean()
{tot=0;for(int i=1;i<=n;i++){nolt[i]=big[i]=lng[i]=0;G[i].clear(); }
}
int main()
{scanf("%d",&T);int tick=0;while(T--){tick++;clean();scanf("%d%d",&n,&k);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);G[u].push_back(v);G[v].push_back(u);}dfs(1,0);/*	cout<<"?剖:\n";for(ll u=1;u<=n;u++)cout<<big[u]<<" "<<lng[u]<<endl;*/for(int i=1;i<=n;i++)nolt[big[i]]=1;for(int i=1;i<=n;i++)if(!nolt[i])b[++tot]=lng[i];sort(b+1,b+tot+1,cmp);ll ans=0;for(int i=1;i<=min(tot,k);i++)ans+=b[i];printf("Case #%d: %lld\n",tick,ans);clean();}return 0;
}
http://www.dtcms.com/a/316497.html

相关文章:

  • bluetooth matlab GFSK 调制解调,误码率统计
  • 委托第三方软件检测机构出具验收测试报告需要做哪些准备?
  • helm部署graph-node服务
  • linux nfs+autofs
  • 并发 Vs 并行
  • 管式土壤墒情监测站在高标准农田的作用
  • 具身智能触觉传感器全景调研
  • HTML 如何转 Markdown
  • 【YOLO学习笔记】YOLOv1详解
  • 亚马逊标品与非标品广告运营:从架构搭建到策略优化的专业方法论
  • Could not load the Qt platform plugin “xcb“ in “无法调试与显示Opencv
  • Natural Language Processing in Computational Creativity: A Systematic Review
  • 2025年08月05日Github流行趋势
  • 3477. 水果成篮 II
  • 电子器械行业的主数据有哪些?
  • Linux NFS 服务部署、客户端配置及 autofs 自动挂载操作指南
  • Tinylog
  • 通俗版23种设计模式解析
  • 机械手的眼睛,视觉系统如何让机器人学会精准抓取
  • GaussDB 常见问题-集中式
  • 05-栈 stack
  • 机器学习算法系列专栏:决策树算法(初学者)
  • TCP如何实现可靠传输?实现细节?
  • 三坐标测量技术解析:从基础原理到斜孔测量难点突破
  • 重生之我在暑假学习微服务第十天《网关篇》
  • Mysql常用语句
  • 广州客户 戴尔R720服务器 liunx系统 RAID5无损升级扩容
  • CTF-XXE 漏洞解题思路总结
  • AI自主任务执行系统 AI Agent无限循环,发任务给AI,让生成脚本,运行执行任务,直到成功。
  • adjtimex系统调用及示例