CSDN传送门
juejin传送门
作者:hans774882968以及hans774882968
题意:有三种类型的客人,他们依次到来,一种反对者,一种支持者,还有一种观望者,即根据当前情况,如果反对数 > 支持数,就投反对,反之投支持的人。现在你有两台服务器,你可以选择给当前来到的客人展示其中一台服务器,问你最多可以获得多少票支持。
有两台服务器,所以把所有dislike都集中到一台服务器即可(提纯是吧)。
from collections import defaultdict
for _ in range(int(input())):
n = int(input())
a = list(map(int, input().split()))
print(sum([1 if v == 1 or v == 3 else 0 for v in a]))
题意:给三个数a,b,c
,让你找到两个数x
和y
,使得x
,y
,gcd(x,y)
这三个数的位数分别是a
,b
,c
。
最简单的方法是,令x
和y
都有c-1
个0,则只需要求x0
和y0
,使得两者满足位数条件且gcd(x0,y0) = 1
。考虑"1" * (a-c+1)
和"1" + "0" * (b-c)
,由辗转相除法可知它们确实互质。
from typing import List
from collections import defaultdict
for _ in range(int(input())):
x, y, z = map(int, input().split())
print("1" * (x - z + 1) + "0" * (z - 1), "1" + "0" * (y - 1))
# c = "1" + "0" * (z - 1)
题意:从前往后给你n
张卡片,每个卡片都有一个颜色,然后有m
次询问,每次询问找到最前面的这个颜色的卡片,输出它的下标,然后把它放到最开头去。
看上去是数据结构,其实是很简单的性质题。我们发现,最前面的某颜色卡片放到最开头后,仍然是最前面的。所以不是最前面的卡片都没有意义,只需要维护每种颜色最前面的卡片的下标。故引入a[x]
表示颜色x
的最靠前面的下标。设当前询问颜色为t
,则修改操作是:对a
中所有小于a[t]
的数加1,然后a[t]
变为1。
因为颜色值域才50,所以可直接暴力。
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 50 + 5;
int n, q, a[N];
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
int main() {
read (n, q);
int mx = 0;
rep (i, 1, n) {
int x;
read (x);
mx = max (mx, x);
if (!a[x]) a[x] = i;
}
rep (i, 1, q) {
int t;
read (t);
printf ("%d%c", a[t], " \n"[i == q]);
rep (j, 1, mx) if (a[j] < a[t]) a[j]++;
a[t] = 1;
}
return 0;
}
题意:让你用从'a'
开始的前m
个字母,构造一个字符串S
(1-indexed),使得满足1<=i
S[i]=S[j]
,S[i+1]=S[j+1]
的i,j
对数最少。
这种构造题我怎么可能会嘛
看了参考链接1,思路是直接贪心地保证当前看上去比较优,即枚举所有候选字母c
,选择las + c
出现次数最少的(实现上,用一个哈希表,把长度为2的字符串映射成m
进制数作为key)。若有多个最少的,应选择最大的字母,因为这样能最大化预留后续的选择空间。这样求出的字符串会是zzyzxzw...
的形式,字典序很大。
看第一个样例9 4
的答案aabacadbb
,对以上方法求出的字符串进行一个简单的映射即可得到。下面的代码使用了那个额外的映射。
法一求出的字符串进行简单映射后,就很有规律,以m = 4
为例:aabacadbbcbdccdd
。不断复制直到长度大于等于n
即可。
法一
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 3e5 + 5;
int n, m, cnt[26 * 26];
char s[N];
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
int main() {
read (n, m);
re_ (i, 0, n) {
int las = i ? s[i - 1] - 'a' : 0, d = -1, mn_d = 1e9;
re_ (j, 0, m) {
if (mn_d >= cnt[26 * las + j]) {
mn_d = cnt[26 * las + j];
d = j;
}
}
cnt[26 * las + d]++;
s[i] = 'a' + d;
}
re_ (i, 0, n) s[i] = 'a' + ('a' + m - 1 - s[i]);
puts (s);
return 0;
}
法二
from collections import defaultdict
n, m = map(int, input().split())
ans = ""
for i in range(m):
ans += chr(97 + i)
for j in range(i + 1, m):
ans += chr(97 + i) + chr(97 + j)
while len(ans) < n:
ans += ans
print(ans[:n])
题意:n * m
矩阵,由o
和*
组成,o
可以涂成红或蓝色。多米诺骨牌是一个1 * 2
的矩阵,红色格子只能横着放骨牌,蓝色格子只能竖着放骨牌。这样就很容易求一种涂色方案可放置的最大骨牌数,求所有2 ^ w
种方案可放置的最大骨牌数的和,模998244353。
首先看一种涂色方案可放置的最大骨牌数,就是红色格子以一个横条为单位,蓝色格子以一个竖条为单位来求,非常简单。这里体现的性质:任意两个横条、任意两个竖条和横条与竖条之间都互不干扰。又注意到矩阵转置一下,竖条就变成横条。因此我们直接求出每个横条的贡献,求和即可。
设一个横条所有涂法的最大骨牌数之和为v
(不考虑矩阵的其他部分),则把矩阵其他部分考虑进来后,该横条对答案的贡献为v * 2^tot
,2^tot
表示矩阵的其他部分的涂色方案总数。
最后只需要知道v
的求法。横条唯一的特征就是格子数,因此设dp[i]
为i
个格子的横条的所有涂法的最大骨牌数之和。边界:dp[0] = dp[1] = 0
。转移:若第i
个格子涂蓝色,则该格子作废,取dp[i-1]
。若第i
个格子涂红色,则:(1)第i-1
个格子涂蓝色,取dp[i-2]
。(2)第i-1
个格子取红色,则最后两个格子所放置的骨牌对前面格子的2^(i-2)
种涂法各有1贡献,取dp[i-2] + 2^(i-2)
。故dp[i] = dp[i-1] + 2*dp[i-2] + 2^(i-2)
。
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 3e5 + 5;
const int mod = 998244353;
int n, m;
vector<string> a;
LL p2[N], dp[N];
void dbg() {
puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
cout << f << " ";
dbg (r...);
}
template<typename Type>inline void read (Type &xx) {
Type f = 1;
char ch;
xx = 0;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar() ) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar() ) xx = xx * 10 + ch - '0';
xx *= f;
}
void read() {}
template<typename T, typename ...R>void read (T &x, R &...r) {
read (x);
read (r...);
}
vector<string> trans (vector<string> &a) {
if (!a.size() ) return vector<string>();
vector<string> b (a[0].size() );
re_ (i, 0, a[0].size() ) {
re_ (j, 0, a.size() ) b[i] += a[j][i];
}
swap (n, m);
return b;
}
LL calc (vector<string> &a, int tot_o) {
LL ans = 0;
re_ (i, 0, n) {
int cnt = 0;
re_ (j, 0, m) {
if (a[i][j] == 'o') ++cnt;
if (a[i][j] != 'o' || j + 1 == m) {
ans = (ans + dp[cnt] * p2[tot_o - cnt] % mod) % mod;
cnt = 0;
}
}
}
return ans;
}
int main() {
read (n, m);
re_ (i, 0, n) {
string t;
cin >> t;
a.push_back (t);
}
p2[0] = 1, p2[1] = 2;
rep (i, 2, N - 5) {
p2[i] = 2 * p2[i - 1] % mod;
dp[i] = (dp[i - 1] + 2 * dp[i - 2] % mod + p2[i - 2]) % mod;
}
int tot_o = 0;
re_ (i, 0, n) re_ (j, 0, m) tot_o += (a[i][j] == 'o');
LL ans = calc (a, tot_o);
a = trans (a);
ans = (ans + calc (a, tot_o) ) % mod;
printf ("%lld\n", ans);
return 0;
}