官方题解
考察点:动态规划
这一题用到的是动态规划。对于 d p [ i ] dp[i] dp[i]表示的是成都为 i i i的字符串方案数是多少。现在考虑前一个状态对于后一个状态的影响。
ll d[N];
int main() {
int n;
cin >> n;
d[2] = 1ll;
for (int i = 3; i <= n; i++)
d[i] = (d[i - 1] * 26 % mod + qpow(26, i - 1, mod) - d[i - 1] - qpow(25, i - 1, mod) + mod) % mod;
ll ans = 0ll;
for (int i = 2; i <= n; i++)
ans = (ans + d[i]) % mod;
cout << ans << endl;
return 0;
}
经典中的经典算法:动态规划
kuangbin动态规划入门专题
考察点:构造
简单的构造题,构造方法有很多。
考察点:dfs,图论
这题还是比较有难度的,对于这个题最主要的是找到性质,一共有两种写法。在这里引用一下别人的一份题解。
上面的讲解都很详细,我在这题不过多赘述。下面是代码。
第一种解法
const int N = 1e5 + 10;
vector<int>G[N];
int ji[N], cnt, col[N];
bool flag = 0;
void dfs(int x, int fa) {
int son = 0;
for (auto v : G[x]) {
if (v == fa)continue;
dfs(v, x); //先遍历子树这样才能保证每个节点被标记
son++;
}
if (son == 0 || ji[x] == 0) {
//如果这个点没被标记但是他不是叶子说明他和他的子节点不一样只能和父亲节点一样
if (ji[fa] != 0) {
flag = 1;
return;
}
ji[fa] = ji[x] = ++cnt;
}
}
void dfs2(int x, int fa) {
for (auto v : G[x]) {
if (v == fa)continue;
if (ji[x] == ji[v])col[v] = col[x];
else col[v] = col[x] ^ 1;
dfs2(v, x);
}
}
int main() {
int n;
cin >> n;
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v), G[v].push_back(u);
}
dfs(1, 0);
if (flag || ji[0]) {
//如果根节点和0被标记了说明根节点与他的子节点都不相同,这是不可能的
puts("-1");
return 0;
}
col[1] = 0; //0/1都一样
dfs2(1,0);
for (int i = 1; i <= n; i++) {
if (col[i] == 1)cout << 'R';
else cout << 'B';
}
cout << endl;
return 0;
}
出题人解法
const int N = 1e5 + 10;
vector<int>G[N];
int sizen[N];
void dfs(int x, int fa) {
//找每个子树的大小
sizen[x] = 1;
for (auto v : G[x]) {
if (v == fa)
continue;
dfs(v, x);
sizen[x] += sizen[v];
}
}
int ji[N], cnt;
int flag = 0;
void dfs2(int x, int fa) {
if (ji[x] == 0) {
int odd = 0, id = 0;;
for (auto v : G[x]) {
if (v == fa)continue;
if (sizen[v] % 2) {
odd++, id = v;
}
if (odd > 1) {
flag = 1;
return;
}
}
if (!odd) {
flag = 1;
return;
}
ji[x] = ji[id] = ++cnt;
}
for (auto v : G[x]) {
if (v == fa)continue;
dfs2(v, x);
}
}
int clo[N];
void dfs3(int x, int fa) {
for (auto v : G[x]) {
if (v == fa)continue;
if (ji[x] == ji[v])clo[v] = clo[x];
else clo[v] = clo[x] ^ 1;
dfs3(v, x);
}
}
int main() {
int n;
cin >> n;
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v), G[v].push_back(u);
}
dfs(1, 0);
dfs2(1, 0);
if (flag) {
cout << -1 << endl;
return 0;
}
clo[1] = 1;
dfs3(1, 0);
for (int i = 1; i <= n; i++) {
if (clo[i] == 1)cout << 'R';
else cout << 'B';
}
cout << endl;
return 0;
}
考察点:并查集
这题主要考的是并查集维护连通块大小和数量,不要被题目吓到,这题虽然代码量大,但是很好想。
这里提供一个并查集经典例题的讲解
这题主要思路是,我们对于这个二维图,把他们的坐标转化成一维即 ( x , y ) − > x ∗ n + y (x,y)->x*n+y (x,y)−>x∗n+y,把坐标转化为一维以后我们用并查集,来维护每个连通块的大小,还有连通块的数量。初始化我们把每个点当成一个单独的连通块(大小为1)。然后对于没个为1的点,我们遍历他的相邻点,如果也为1,就合并。同时因为每次合并的操作对连通块数量的改变最多为1,答案很好维护。
下面是代码。
ll qpow(ll a, ll b, ll mod) {
ll res = 1; for (; b > 0; b >>= 1) {
if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
inline ll inv(ll a, ll p) {
return qpow(a, p - 2, p); } //这里是求逆元的操作
const int N = 250015;
char s[505][505];
int dx[4] = {
1,-1,0,0 };
int dy[4] = {
0,0,1,-1 };
int pre[N];
int sizen[N];
int n;
int get_id(int i, int j) {
return i * n + j;
}
int find(int x) {
return x == pre[x] ? x : pre[x] = find(pre[x]);
}
ll ans = 1ll; //记录答案
int cnt = 0; //记录连通块的数量
void unioun(int x, int y) {
int xx = find(x), yy = find(y);
if (xx == yy)return;
ans = ans * inv(cnt, mod) % mod;
cnt--;
ans = ans * inv(sizen[xx], mod) % mod * inv(sizen[yy], mod) % mod;
ans = ans * (sizen[xx] + sizen[yy]) % mod;
sizen[xx] += sizen[yy];
pre[yy] = xx;
}
int main() {
#ifdef MPDFDFL
freopen("D:/input.txt", "r", stdin);
//freopen("D:/output.txt", "w", stdout);
#endif
cin >> n;
for (int i = 0; i < n; i++)
scanf("%s", s[i]);
for (int i = 0; i <= n * n + 10; i++)
pre[i] = i;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
if (s[i][j] == '1')
ans = (ans * ++cnt) % mod, sizen[get_id(i, j)] = 1;
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
if (s[i][j] == '1') {
for (int k = 0; k < 4; k++) {
int sx = dx[k] + i, sy = j + dy[k];
if (s[sx][sy] == '1')
unioun(get_id(i, j), get_id(sx, sy));
}
}
}
int q;
cin >> q;
while (q--) {
int x, y;
cin >> x >> y;
if (s[x][y] == '1') {
cout << ans << endl;
continue;
}
s[x][y] = '1';
sizen[get_id(x, y)] = 1;
cnt++;
ans = ans * cnt % mod;
int flag = 0;
for (int i = 0; i < 4; i++) {
int sx = dx[i] + x, sy = y + dy[i];
if (s[sx][sy] == '1') {
flag = 1;
unioun(get_id(sx, sy), get_id(x, y));
}
}
cout << ans << endl;
}
return TIME;
}
考察点:计算几何
高中立体几何知识,自己推公式即可。
考察点:贪心
签到题。
考察点:模拟
按照题意模拟即可
考察点:欧拉降幂,找规律
这题官方题解里给的是找规律。这里不在多讲,主要讲一下欧拉降幂的解法。
这是一个欧拉降幂的算法讲解
这一题其实是欧拉降幂的一个经典例题的延申。
如果懂了上面哪一题以后这题就非常好理解。很明显这题虽然不是无限的,但是模数是固定的,就是10,所以根据欧拉函数,他最多迭代四层,之后答案就不会在改变了。这里我们控制一下迭代层数,还有每次次迭代处理的模数,这题就解决了。
ll qpow(ll a, ll b, ll mod) {
ll res = 1; for (; b > 0; b >>= 1) {
if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
const int mod = 1e9 + 7;
int phi[15];
int mo(string x,int MOD) {
int len = SZ(x);
int res = 0;
for (int i = 0; i < len; i++)
res = (res*10 + x[i] - '0') % MOD;
return res;
}
int f(string x, int MOD,int cnt) {
if (MOD == 1)return 0;
if (cnt == 1)return mo(x, MOD);
return (qpow(mo(x, MOD) , f(x, phi[MOD], cnt - 1) + phi[MOD], MOD) + MOD) % MOD;
}
int main() {
phi[10] = 4, phi[4] = 2, phi[2] = 1;
string a, b;
cin >> a >> b;
int cnt = 0;
if (SZ(b) > 1)cnt = 10;
else cnt = min(10, b[0] - '0');
cout << (f(a, 10, cnt) % 10 + 10) % 10 << endl;
return 0;
}
考察点:构造
这题同样是一个简单的构造,构造方法很多这里不在多讲。
考察点:素数筛
这里引用一下别人的一个题解讲的很好。
#include
#include
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int N = 2e8 + 10;
ll Pow(ll x, ll y)
{
ll res = 1;
while (y)
{
if (y & 1)
res = res*x%mod;
y >>= 1;
x = x*x%mod;
}
return res;
}
bool vis[N]; int p[12000000];
int tot;
void init()
{
for (int i = 2; i < N; i++)
{
if (!vis[i])
p[++tot] = i;
for (int j = 1; j <= tot&&i*p[j] < N; j++)
{
vis[i*p[j]] = 1;
if (i%p[j] == 0) break;
}
}
}
int main()
{
init();
int n;
scanf("%d", &n);
if (n <= 5)
{
puts("empty");
exit(0);
}
ll ans = 1;
int x = n / 3;
int cnt = 0;
while (x > 1) x /= 2, cnt++;
ans = ans*Pow(2, cnt) % mod;
int pp = sqrt(n);
for (int i = 2; i <= tot&&p[i]<=n; i++)
{
if (p[i] > pp)
{
if (n / p[i] > 1)
ans = ans*p[i] % mod;
}
else
{
cnt = 0;
x = n / 2;
while (x >= p[i]) x /= p[i], cnt++;
ans = ans*Pow(p[i], cnt) % mod;
}
}
printf("%lld\n", ans);
return 0;
}