Problem A magic

给出一个字符串$S$,和数字$n$,要求构造长度为$n$只含有小写字母的字符串$T$,

使得在$T$中存在删除且仅删除一个子串使得$S=T$成立。

输出$T$的构造方案数,mod 998244353的值。

对于$100 \% $的数据 $2  \leq n \leq 10^{18} , |S| \leq 10^6$

Sol : 考虑$T$合法的条件是和$S$有相同的前缀和相同的后缀,且相同前后缀长度和是$|S|$

若最长公共前缀长度为$0$ ,那么说明$S$和$T$最后$|S|$位相同,合法情况$T$的取值有$26^{n - |S|}$ 种。

  若最长公共前缀长度不为$0$ ,那么说明前半部分至少有$k$是$S$的前缀,后半部分就有$|S| - k $的长度是后缀,这个时候由于倒数$|S| - k$ 个 不能和上一次一样,这个位置只有$25$种可能,其他位置是$26$种可能,这种情况下方案数时$26^{n-|S|-1}$

最后答案就是$26^n - 26^{n-1} - |S|\times 25 \times 26^{n-|S|-1}$

  注意需要特判$n = |S|$的情况,答案就是$26 ^ n - 1$

 复杂度是$O(log_2 n)$

#include<bits/stdc++.h>
using namespace std;
const long long mod=;
long long n,m;
char tmp[];
long long Pow(long long x,long long k)
{
if(k<) return 0ll;
if(!k) return 1ll;
long long res=Pow(x,k/);
res=res*res%mod;
if(k%) res=res*x%mod;
return res;
}
int main()
{
scanf("%lld %s",&n,tmp);
m=strlen(tmp);
printf("%lld",(long long)(Pow(26ll,n)-(Pow(26ll,n-m)%mod+(m*25ll%mod)*Pow(26ll,n-m-)%mod)%mod+mod)%mod);
return ;
}

A.cpp

  Problem B graph

  给出可重边无自环不保证连通的无向图$G$ ,询问$u $到$v$简单路径上经过边权的最大值最小。

  对于$100\% $ 的数据$n,m,q \leq 3 \times 10^5$

Sol: 建出最小生成树(在建树过程考虑了重边了)。、

    然后用并查集维护连通性。

    最大边权最小等价于在最小生成树树上路径的最大值。

    复杂度就是$O(m log_2 m)$

# include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + ;
map<int,int>mp[N];
int g[N][],d[N][],dep[N],fc[N],n,m,q;
vector<pair<int , int> >E[N];
struct edge{
int u,v,w;
};
vector<edge>Edge;
bool cmp(edge a,edge b){return a.w < b.w;}
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void write(int x)
{
if (x<) x=-x,putchar('-');
if (x>) write(x/);
putchar(''+x%);
}
void writeln(int x)
{
write(x); putchar('\n');
}
int father(int x)
{
if (fc[x]==x) return x;
return fc[x]=father(fc[x]);
}
void kruskal()
{
sort(Edge.begin(),Edge.end(),cmp);
for (int i = ; i <= n; i++) fc[i] = i;
for (int i = ; i < Edge.size(); i++) {
int u=Edge[i].u,v=Edge[i].v,w=Edge[i].w;
int fx = father(Edge[i].u),fy = father(Edge[i].v);
if (fx == fy) continue;
fc[fx] = fy;
E[u].push_back(make_pair(v,w));
E[v].push_back(make_pair(u,w));
}
}
void dfs(int u,int fa)
{
dep[u]=dep[fa]+; g[u][]=fa;
for (int i=;i<E[u].size();i++) {
int v=E[u][i].first,w=E[u][i].second;
if (v==fa) continue;
d[v][]=w;
dfs(v,u);
}
}
void init()
{
for (int i = ; i<=n ; i++)
if (!dep[i]) dfs(i,);
for (int i = ; i <= ; i++)
for (int j = ; j <= n ; j++)
g[j][i] = g[g[j][i-]][i-],
d[j][i] = max(d[j][i-] , d[g[j][i-]][i-]);
}
int query(int u,int v)
{
int fx = father(u), fy = father(v);
if (fx != fy) return -;
if (dep[u] < dep[v]) swap(u,v);
int ret = ;
for (int i = ; i >= ; i--)
if (dep[g[u][i]] >= dep[v])
ret = max(ret,d[u][i]),u=g[u][i];
if (u == v) return ret;
for (int i = ; i >= ;i--)
if (g[u][i] != g[v][i])
ret = max(max(ret , d[u][i]) , d[v][i]),
u = g[u][i] , v = g[v][i];
return max(max(ret,d[u][]),d[v][]);
}
int main()
{
n=read();m=read();q=read();
for (int i=;i<=m;i++) {
int u=read(),v=read(),w=read();
if (mp[u].count(v) != ) w = min(w , mp[u][v]);
mp[u][v] = mp[v][u] = w;
}
map<int,int>::iterator it;
for (int i = ; i <= n ; ++i )
for (it = mp[i].begin() ; it != mp[i].end() ; ++it)
Edge.push_back((edge){i , it->first , it->second});
kruskal(); init();
while (q--) {
int u=read(),v=read();
writeln(query(u,v));
}
return ;
}

B.cpp

Problem C number

  定义不算前导零,只由两个数字构成的数为“好数”,如$101010$, $11111$

给出$T$个询问,询问$x$至少由几个好数相加组成的(可以同一个数用多次)。

  对于$100\%$的数据$1 \leq n \leq 10^{18} ,1 \leq T \leq 100$

  Sol:考虑$01$ , $02$ , $03$ , $04$最多四个数字就可以创造世界了,所以我们只需要判断$3$及以下的情况,剩余情况就输出$4$

  我们可以枚举$C_{10}^{2} = 45$种选择数的方案$mask[i]$来构成这些数,然后用dp验证即可。

  我们只至少这若干个数加起来是多少,我们要还原他为0,才能检验是否合法。

  对于每个三个数累加的方案,我们都有这三个数中任意选2个任意选1个不选这7种子方案,也能获得相同的效果,我们特殊考虑,记录在$Sub[i]$中。

  我们可以预处理出每个个选择数的方案,可以构成哪些最小合法的数(显然这些数都是小于等于$3 \times 9 =27$的)

设$f[i][j]$表示使用标号为$i$的方案,到达$j$数位上的信息,这个信息是一个3位二进制数,分别表示高位向低位退位为$i , i\in[0,2]$是否合法。

  转移的话可以用位运算转移。

  最后如果当前数位为1,并且可以退0位的方案是ok的,那么我们就对对应取数的个数求min即可。(如果无法构成答案就是4了)

  复杂度是$O(T \times C_{45}^{3} \times 18 \times 3 \times 3)$

# include <bits/stdc++.h>
# define int long long
using namespace std;
int mask[],f[][],s[][][],val[],a[];
bool ok[][];
int size;
vector<int>Sub[];
signed main()
{
for (int i = ; i <= ; i++ )
for (int j = i + ; j <= ; j++ )
mask[++mask[]] = i * + j;
memset(ok, false, sizeof(ok));
int t = mask[] ; mask[] = ;
for (int i = ;i <= t ; i++)
for (int j = i ; j <= t ; j++)
for (int k = j ; k <= t ;k++) {
val[++size] = - (i==) - (j==) - (k==);
ok[size][mask[i]/ + mask[j]/ + mask[k]/] = ok[size][mask[i]% + mask[j]/ + mask[k]/] = true;
ok[size][mask[i]/ + mask[j]% + mask[k]/] = ok[size][mask[i]/ + mask[j]/ + mask[k]%] = true;
ok[size][mask[i]% + mask[j]% + mask[k]/] = ok[size][mask[i]% + mask[j]/ + mask[k]%] = true;
ok[size][mask[i]/ + mask[j]% + mask[k]%] = ok[size][mask[i]% + mask[j]% + mask[k]%] = true;
s[i][j][k] = s[i][k][j] = s[j][i][k] = s[j][k][i] = s[k][i][j] = s[k][j][i] = size;
if (s[][j][k] != size) Sub[size].push_back(s[][j][k]);
if (s[i][][k] != size) Sub[size].push_back(s[i][][k]);
if (s[i][j][] != size) Sub[size].push_back(s[i][j][]);
if (s[][][k] != size) Sub[size].push_back(s[][][k]);
if (s[][j][] != size) Sub[size].push_back(s[][j][]);
if (s[i][][] != size) Sub[size].push_back(s[i][][]);
if (s[][][] != size) Sub[size].push_back(s[][][]);
}
int T; scanf("%lld",&T);
while (T--) {
memset(f, , sizeof(f));
int x; scanf("%lld",&x); a[] = ;
while (x) { a[++a[]] = x%; x/=;}
for (int i = ; i<= size; i++) f[i][a[]+] = ;
for (int i = a[] ; i>= ; i--) {
for (int j = ; j <= size ; j++) {
for (int last = ; last <= ; last++) if (f[j][i+] & (<<last))
for (int to = ; to <= ; to++) if (last* + a[i] - to >= && ok[j][last* + a[i] - to]) {
f[j][i] |= (<<to) ;
}
for (int k = ;k < Sub[j].size() ; k++) {
int tmp = Sub[j][k] ;
f[j][i] |= f[tmp][i];
}
}
}
int ans = ;
for (int i = ; i <= size ; i++) if (f[i][] & ) ans = min(ans , val[i]);
printf("%lld\n",ans);
}
return ;
}

C.cpp

HGOI20190811 省常中互测4的更多相关文章

  1. HGOI 20190816 省常中互测8

    Problem A  有两条以(0,0)为端点,分别经过(a,b),(c,d)的射线,你要求出夹在两条射线中间,且距离(0,0)最近的点(x,y) 对于$100\%$的数据满足$1 \leq T \l ...

  2. HGOI20190814 省常中互测7

    Problem A 中间值 对于$2$个非严格单增序列$\{A_n\} , \{B_n\}$,维护下列两个操作: 1 x y z: (x=0)时将$A_y = z$ , (x=1)时将$B_y = z ...

  3. HGOI20190813 省常中互测6

    Problem A 蛋糕 将$n \times m $大小的蛋糕切成每块为$1 \times 1$大小的$n\times m$块. 交换任意两块蛋糕的切割顺序的方案算作一种. 对于$100 \%$的数 ...

  4. HGOI20190810 省常中互测3

    Problem A  夏洛特 若当前处在点$(x,y)$下一时刻可以向该点四周任意方向走动一步, 初始在$(0,0)$是否存在一条合法的路线满足下列$n$个限制: 每一个限制形如$t_i , x_i ...

  5. HGOI20190809 省常中互测2

    Problem A 时之终结 构造一个含有$n$个节点的无重边无自环的有向图, 使得从$1$出发,每一次经过一条$(u,v) (u < v)$的边到达节点$n$的方案恰好有$y$种. 对于$10 ...

  6. HGOI20190808 省常中互测1

    Problem A  sum 给出$n$个元素的序列$\{a_i\}$,求出两个不相交连续子序列的最大元素和. 即对于$1 \leq A \leq B \leq C \leq D \leq n$最大化 ...

  7. HGOI20190812 省常中互测5

    Task 1 辩论 有N 个参加辩论的候选人,每个人对这两个议题都有明确的态度,支持或反对.作为组织者,小D 认真研究了每个候选人,并给每个人评估了一个非负的活跃度,他想让活跃度之和尽可能大.选出的候 ...

  8. 【2018集训队互测】【XSY3372】取石子

    题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...

  9. 【CH 弱省互测 Round #1 】OVOO(可持久化可并堆)

    Description 给定一颗 \(n\) 个点的树,带边权. 你可以选出一个包含 \(1\) 顶点的连通块,连通块的权值为连接块内这些点的边权和. 求一种选法,使得这个选法的权值是所有选法中第 \ ...

随机推荐

  1. 并发编程 深入分析Volatile的实现原理

    在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”.可见性的意思是当一个线 ...

  2. EM 算法(二)-KMeans

    KMeans 算法太过简单,不再赘述 本文尝试用 EM 算法解释 KMeans,而事实上 KMeans 算是 EM 的一个特例 EM 算法是包含隐变量的参数估计模型,那对应到 KMeans 上,隐变量 ...

  3. java实现spark常用算子之mapPartitions

    import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.a ...

  4. 订单支付倒计时-剩余时间xx小时xx分xx秒

    //<input type="hidden" id="endTime" value="1554912000000"> 结束时间 ...

  5. Vue中,过滤器的使用方法!

    Vue.js允许自定义过滤器,可被用于一些常见的文本格式化.过滤器可以用在两个地方:双花括号插值和v-bind表达式.过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示:(借官方的 ...

  6. 学习.NET中的AppDomain

    学习.NET中的AppDomain 什么是AppDomain?AppDomain是一组程序集的逻辑容器,AppDomain是为了提供隔离而设计的.它提供了保护.配置和终止其中每一个应用程序的隔离 Ap ...

  7. 24、Nginx缓存web服务

    通常情况下缓存是用来减少后端压力, 将压力尽可能的往前推, 减少后端压力,提高网站并发延时 1.缓存常见类型 服务端缓存 代理缓存, 获取服务端内容进行缓存 客户端浏览器缓存 Nginx代理缓存原理 ...

  8. 3.(基础)tornado的接口调用顺序与模板

    上一节介绍了tornado的请求与响应,这一节介绍tornado的接口调用顺序和模板 首先都有哪些接口呢?作用是什么呢?并且都有的时候,执行顺序是怎么样的呢? 接口 1.initialize,表示初始 ...

  9. Java入门指南-03 操作符与表达式

    一.赋值操作符 在 Java 语言里,等号称为赋值操作符.例:a = b + 100;注意,不要把 Java 语言理解为数学.在 Java 里,这个等号的作用是“赋值”,即右侧的值赋给左边的变量. 要 ...

  10. 自学Python5.6-面向对象三大基本特征_多态

    自学Python之路-Python基础+模块+面向对象自学Python之路-Python网络编程自学Python之路-Python并发编程+数据库+前端自学Python之路-django 自学Pyth ...