链接:https://ac.nowcoder.com/acm/contest/885/A
给你一个数 n (1 <= n <= 100) ,让你输出一个数 x ,x 满足两个条件 : 1 . x 是 n 的倍数,2 . x 的每一位数字加起来的和也是 n 的倍数。
暴力打表到70多就比较满了,所以肯定是构造,怎么构造呢? 首先先满足第一个条件,用很多 n 拼接来构造,比如 n = 15 。可以用 好多15 如: 1515151515 这个就满足那两个条件,由于用 n 来拼接的肯定满足是 n 的倍数,然后不断拼接直到每一位的和也是 n 的倍数就可以了。
#include
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<
链接:https://ac.nowcoder.com/acm/contest/885/B
已知: 给你 n,MOD,求 。
有递推方程显然用矩阵快速幂,但是因为 n 特别大,似乎使用十进制加速的快速幂才可以过。
#include
#define up(i, x, y) for(ll i = x; i <= y; i++)
#define down(i, x, y) for(ll i = x; i >= y; i--)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<= 1; i--)
{
ll t = str[i] - '0';
for(ll i = 1; i <= t; i++)
{
M = M * base;
}
base = base * base;
tmp = base;
base = base * base;
base = base * base;
base = base * tmp;
}
printf("%lld\n", (M.A[2][1] * x1 + M.A[2][2] * x0) % mod);
}
给你一个a串,一个b串,让你求a串中有多少个子序列换成十进制数比b串换成十进制数大。3000 >= |a| >= |b| >= 1 .
分两种情况讨论
第一种就是当 a 串子序列的长度大于 b 串时,这时候一定满足条件,但是注意不能有前0 ,这时候就枚举 a 序列的每一位,然后只要非0,就把后面的算下组合数加起来就行了。
第二种就是当 a 串子序列的长度等于 b 串时,这时候需要dfs搜索了,但是会超时,把dfs改成记忆化就可以过了,注意求组合数要打表。
#include
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["< n || j > m) return 0;
if(dp[i][j] != -1) return dp[i][j];
if(a[i] > b[j])
{
if(n - i >= m - j)
return dp[i][j] = (dfs(i + 1, j) + C[n - i][m - j]) % mod;// % mod;
return dp[i][j] = dfs(i + 1, j);
}
else if(a[i] == b[j])
{
return dp[i][j] = (dfs(i + 1, j + 1) + dfs(i + 1, j)) % mod;
}
else
{
return dp[i][j] = dfs(i + 1, j);
}
}
int main()
{
init();
int T; scanf("%d", &T); while(T--)
{
scanf("%d %d", &n, &m);
for(int i = 0; i <= n; i++)
for(int j = 0; j <= m; j++)
dp[i][j]= -1;
scanf("%s", a + 1);
scanf("%s", b + 1);
ans = dfs(1, 1);
for(int i = 1; i <= n - m + 1; i++)
{
if(a[i] != '0')
for(int j = m; j <= n - i; j++)
ans = (ans + C[n - i][j]) % mod;
}
printf("%lld\n", ans);
}
}
链接:https://ac.nowcoder.com/acm/contest/885/H
让你猜测一个长度为 n 的字符串是什么。然后会给你 m * (m - 1) / 2 条提示。并且这个字符串是由前 m 个小写字母组成。每一个提示中会先给你两个不同的小写字符,然后再给你一个len,代表下一个要给你的字符串的长度。然后再给你一个长度为 len 的字符串,这个字符串是把真正的 长度 为 n 的字符串中的那两个小写字符按照源字符串中的顺序抽取出来的。0 <= len <= n ,当取0的时候也说明源字符串没有这俩字符。
因为是按照初始字符串中的顺序提取出来的,那么就给每一个字符一个编号,然后按照给的顺序连有向边,保证字符之前的前后关系,然后就可以建立一个有向图了。对于这个有向图跑拓扑排序,如果无法跑完,说明有换前后提示有矛盾输出 -1。如果可以跑完就直接是答案了。需要注意的是:如果他给你的提示中的字符不够n个,自己需要补充上,并且不能使用他提示中给的,因为他提示中给的肯定是已经出现的了,数目也是固定的,不可以修改。同时需要注意要添加前 m 个小写字母,题意要求。
在给每个字符编号时,可以设一个 id[ i ][ j ] 来确定编号,意思是:字母 i 在出现的第 j 次的编号是 id[ i ][ j ] ,这样编号就很方便了,具体细节可以参考代码。
#include
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["< vec[maxn];
map mp;
char s[50];
char str[maxn];
int du[maxn];
int mp2[30];
int pd[30];
int main()
{
int cnt = 0;
int m2;
int n, m; scanf("%d %d", &n, &m);
m2 = m * (m - 1) / 2;
int len;
memset(pd, -1, sizeof(pd));
int cuo = 0;
while(m2 --)
{
scanf("%s%d",s, &len);
for(int i = 0; s[i] ;i++)
{
mp2[ s[i] - 'a' ] = 1; // 标记是否出现过,出现过就不可以使用该字母补
if(s[i] -'a' >= m)
{
cuo = 1;
goto stop;
}
}
if(len == 0) continue;
scanf("%s", str + 1);
memset(used, 0, sizeof(used));
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= len; i++)
{
int t = str[i] - 'a';
vis[t]++;
if(id[t][vis[t]] == 0)
{
id[t][vis[t]] = ++cnt; // 编号
mp[cnt] = 'a' + t;
}
used[i] = id[t][vis[t]]; // 保存前后关系
}
for(int i = 1; i < len; i++)
{
vec[ used[i] ].push_back( used[i + 1] ); // 建图
du[used[i + 1]]++;
}
stop : {};
}
if(cuo)
{
puts("-1");
return 0;
}
if(cnt < n) // 如果提供的个数不足 n 个,那么就补上,补的必须是未出现的而且要小于 m
{
for(int i = 0; i < m; i++)
{
if(mp2[i] == 0)
{
int tmp = n - cnt;
for(int j = 1; j <= tmp; j++)
{
++cnt;
mp[cnt] = 'a' + i;
}
break;
}
}
}
if(cnt < n) // 不能补
{
printf("-1\n");
return 0;
}
queue que;
for(int i = 1; i <= n; i++)
{
if( du[i] == 0 )
{
que.push(i);
}
}
string ans = "";
int f = 0;
while(!que.empty())
{
int t = que.front(); que.pop();
ans += mp[t];
for(int i = 0; i < vec[t].size(); i++)
{
int v = vec[t][i];
du[v]--;
if(du[v] == 0) que.push(v);
}
}
if(ans.length() != n) puts("-1"); // 矛盾,拓扑没跑完,肯定不成立
else cout <