A.Sum of Odd Integers
题意:
给定,
,问
是否能被
个互不相同的奇数表示。
题解:
先判断与
的奇偶性,如果奇偶性不同则肯定不行
再判断与
的关系,如果
就可以
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
void solve()
{
ll n, k;
scanf("%lld%lld", &n, &k);
if ((n & 1) != (k & 1))
{
puts("NO");
return;
}
puts((n >= k * k) ? "YES" : "NO");
}
int main()
{
int t;
for (scanf("%d", &t); t >= 1; t--)
solve();
} B.Princesses and Princes
题意:
给定个公主,每个公主都有自己心仪的王子,按照公主的编号从小到大,每次为她选择她心仪的编号最小的王子,问现在是不是最优匹配,如果不是应该在哪个公主的心仪王子中添加哪个王子。保证王子公主一一配对。
题解:
按公主出现的顺序每次把第一个出现的没有匹配过的王子配对给他,最后扫描一遍所有的公主选出没有匹配的,再扫描一遍所有的王子,如果两者都存在就输出并将两人匹配,否则输出
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
bool p[maxn], pos[maxn];
void solve()
{
int n;
scanf("%d", &n);
memset(pos, 0, sizeof(pos));
for (int i = 1; i <= n; i++)
{
int k;
scanf("%d", &k);
p[i] = 0;
while (k--)
{
int q;
scanf("%d", &q);
if (!p[i] && !pos[q])
{
p[i] = 1;
pos[q] = 1;
}
}
}
for (int i = 1; i <= n; i++)
if (!p[i])
for (int j = 1; j <= n; j++)
if (!pos[j])
{
puts("IMPROVE");
printf("%d %d\n", i, j);
return;
}
puts("OPTIMAL");
}
int main()
{
int t;
for (scanf("%d", &t); t >= 1; t--)
solve();
} C.Game with Chips(构造)
题意:
有个点,每次操作可以把所有点整体向
,
,
,
移动一格,如果有的点到了边还要移动就会保持不动。问是否可以在
步内完成让每个点经过它的必经之点,如果可以则输出移动序列。
。
题解:
因为给定的最大步数是,所以通过适合的构造方案能保证可以遍历全部格点,具体构造方案如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
int main()
{
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
string ans;
ans += string(n - 1, 'D') + string(m - 1, 'R');
for (int i = 0; i < m; i++)
{
ans += string(n - 1, (i & 1) ? 'D' : 'U');
if (i != m - 1)
ans += 'L';
}
cout << ans.size() << endl;
cout << ans << endl;
return 0;
} D.Infinite Path
题意:
给定一个长度为n的排列,位置
的颜色为
。定义一条无穷路径指的是:存在这样一个无穷序列
,该序列对应的每个位置颜色相同;再定义
阶迭代指的是:对每个位置
,进行
次迭代后得到的序列(即
迭代为
,再迭代为
)。询问至少进行几阶迭代后,至少存在一条无穷路径。
题解:
首先很自然的想到从每个到
连一条有向边,那么一定会构成若干个不相交的环。
阶迭代的意思是在每个环中每相邻的
个节点重新组成一个环,那么我们只要对每个环进行判断在数列
的所有环中,能否找到一个等差
,使得环上所有满足等差关系的位置:
等位置的颜色相同,维护这个最小的
就是答案了,这个
就是每个环长度的各个因子,对于每个长度的因子可以
预处理
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
bool vis[maxn];
int p[maxn], c[maxn];
vector<int> d[maxn];
int cal(vector<int> loop)
{
int mn = INF;
for (auto len : d[loop.size()])
{
for (int i = 0; i < len; i++)
{
bool flag = true;
for (int j = i; j < loop.size(); j += len)
{
if (c[loop[i]] != c[loop[j]])
{
flag = false;
break;
}
}
if (flag)
mn = min(mn, len);
}
}
return mn;
}
int main()
{
for (int i = 1; i < maxn; i++)
for (int j = i; j < maxn; j += i)
d[j].push_back(i);
int t;
for (scanf("%d", &t); t >= 1; t--)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &p[i]);
for (int i = 1; i <= n; i++)
{
scanf("%d", &c[i]);
vis[i] = false;
}
int ans = n;
for (int i = 1; i <= n; i++)
{
if (vis[i])
continue;
vector<int> loop;
int k = i;
while (!vis[k])
{
loop.push_back(k);
vis[k] = true;
k = p[k];
}
ans = min(ans, cal(loop));
}
printf("%d\n", ans);
}
return 0;
} E.Count The Blocks
题意:
定义“块”表示连续相同数字的长度。给定,连续写下
这些数,对于每一位数字不够
位的补足前导
,求
长度为
的块有多少个,对
取模。
题解:
打表找规律发现
因此可以发现
或者
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const ll mod = 998244353;
ll ans[maxn];
int main()
{
int n;
scanf("%d", &n);
ans[1] = 10, ans[2] = 180, ans[3] = 2610;
for (int i = 4; i <= n; i++)
ans[i] = ((20 * ans[i - 1] - 100 * ans[i - 2]) % mod + mod) % mod;
for (int i = n; i >= 1; i--)
printf("%lld ", ans[i]);
puts("");
return 0;
} F.AND Segments
题意:
给定,下面
行,每行给定三个数:
,已知长度为
的序列
满足
,问合法的序列
的数量,
。其中所有数
。
题解:
注意到,考虑枚举每一位来做。我们记录这一位必须为
的区间,可以枚举每个
用差分实现。然后记录必须为
的区间,令
表示最大的
满足
这一段都为
。
的时候考虑:如果
的
,直接
就可以了。如果
的
,说明这个数的这一位不可以为
,考虑
的
,若
,说明它之前没有满足的
,那么
,直接沿用上一个数的方案数。但是若
,说明前面有满足的
,那就必须减去
,相当于
这种思想,然后
。最后根据乘法原理把每一层的
乘起来就行了。
(这题我也没怎么看懂,转自这位博主的题解:链接)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 5e5 + 5;
const int INF = 0x3f3f3f3f;
const ll mod = 998244353;
int n, k, m;
int x[maxn], l[maxn], r[maxn];
ll dp[maxn];
int a[maxn], b[maxn];
int main()
{
scanf("%d%d%d", &n, &k, &m);
for (int i = 1; i <= m; ++i)
scanf("%d%d%d", &l[i], &r[i], &x[i]);
ll ans = 1;
dp[0] = 1;
for (int t = 0; t < k; t++)
{
for (int i = 1; i <= n + 1; i++)
a[i] = 0, b[i] = 0;
for (int i = 1; i <= m; i++)
{
if (x[i] >> t & 1)
a[l[i]]++, a[r[i] + 1]--;
else
b[r[i] + 1] = max(b[r[i] + 1], l[i]);
}
for (int i = 1; i <= n + 1; i++)
{
a[i] += a[i - 1];
b[i] = max(b[i], b[i - 1]);
}
for (int i = 1; i <= n + 1; i++)
{
if (!a[i])
{
dp[i] = dp[i - 1];
if (b[i])
dp[i] = (dp[i] - dp[b[i] - 1] + mod) % mod;
}
else
dp[i] = 0;
dp[i] = (dp[i - 1] + dp[i]) % mod;
}
ans = ans * (dp[n + 1] - dp[n] + mod) % mod;
}
cout << ans << endl;
} 
京公网安备 11010502036488号