oj: 牛客
oj: 牛客
排序后直接输出。
#pragma GCC optimize(2)
#include
#define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i)
using namespace std;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
int n;
vector< pair<int, string> > a;
void init() {
a.resize(n * 3);
}
void sol() {
init();
char s[21];
int x;
_for(i, n * 3) cin >> a[i].second >> a[i].first;
sort(a.begin(), a.end());
_for(i, n) {
printf("ACM-%d", i);
vector<string> t;
for(int j = 0; j < 3; ++j) t.push_back(a[i * 3 + j].second);
for(int j = 2; j >= 0; --j) cout << " " << t[j];
cout << "\n";
}
}
int main() {
int T = read();
_for(i, T) {
n = read();
sol();
}
return 0;
}
oj: 牛客
待补
oj: 牛客
观察后发现是斐波那契数列,直接暴力递推,中间对 m m m 取模。不要忘记最后先加上一个 m m m 再对 m m m 取模,否则会出现负数。
#pragma GCC optimize(2)
#include
#define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i)
using namespace std;
typedef long long LL;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
int main() {
int T = read();
_for(i, T) {
LL n = read(), m = read();
LL a = 1, b = 0, c = 1;
_for(j, n) {
c = (a + b) % m;
a = b, b = c;
}
printf("%lld\n", (c - 1 + m) % m);
}
return 0;
}
oj: 牛客
待补
oj: 牛客
只要两个字符串中的每一个字符的出现次数都一样,我们就认为这两个字符串是一样的。
只要一个串的出现次数t大于1,那么这个串就一定能作为回文串的两端中的某一段,并且出现偶数次。对答案的贡献是 2 m ⌊ t 2 ⌋ 2m\lfloor \frac{t}{2}\rfloor 2m⌊2t⌋。
我们在出现次数为1的串里找一个这样的串: 串内出现次数为奇数的字符 的个数不超过1。这样我们就能把这个串作为回文中心。对答案的贡献是 m m m。
#pragma GCC optimize(2)
#include
#define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i)
using namespace std;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
map< string, int > mp;
int n, m;
void init() {
mp.clear();
}
int che(string s) {
map<char, int> tem;
for(char c : s) ++tem[c];
int cnt = 0;
for(auto i : tem) {
cnt += (i.second & 1);
}
return cnt <= 1;
}
void sol() {
init();
string s;
_for(i, n) {
cin >> s;
sort(s.begin(), s.end());
++mp[s];
}
int ans = 0, f = 0;
for(auto i : mp) {
if(i.second > 1) ans += i.second / 2 * 2 * m;
else if(f == 0) {
if(che(i.first)) {
ans += m;
f = 1;
}
}
}
printf("%d\n", ans);
}
int main() {
n = read(), m = read();
sol();
return 0;
}
oj: 牛客
由于询问的n的值不超过 10000 10000 10000,所以我们筛出 15000 15000 15000 以内的素数就足够了。
先判断 n n n 是不是素数,这一步可以合并到寻找不小于 n n n 的最小的素数中。
分别找出不小于 n n n 的最小的素数和比 n n n 小的最大的素数。
不小于 n n n 的最小的素数是 *lower_bound(arr.begin(), arr.end(), d)
。判断值是否与 n n n 相等。
比 n n n 小的最大的素数是 *upper_bound(arr.begin(), arr.end(), d)
。
如果 n n n 不是素数,则二者与 n n n 的距离取最小值。
#include
#define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i)
using namespace std;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
vector<int> arr;
int vis[1000006];
void doit(int maxnum) {
for(int i = 2; i <= maxnum; ++i) {
if(!vis[i]) arr.push_back(i);
for(int j = 0; j < arr.size() && arr[j] * i <= maxnum; ++j) {
vis[arr[j] * i] = 1;
if(i % arr[j] == 0) break;
}
}
}
int main() {
doit(15000);
int T = read();
_for(i, T) {
int d = read();
int p = lower_bound(arr.begin(), arr.end(), d) - arr.begin();
if(d == arr[p]) printf("YES\n");
else {
int pp = upper_bound(arr.begin(), arr.end(), d) - arr.begin() - 1;
printf("%d\n", min(d - arr[pp], arr[p] - d));
}
}
return 0;
}
oj: 牛客
#include
using namespace std;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
struct poi {
int s;
vector<int> e, m;
poi(){}
poi(double x) {
e.clear(); m.clear();
s = (x <= 0); x = fabs(x);
int cnt = 15;
while(x >= 2) {
++cnt;
x /= 2;
}
while(x < 1) {
--cnt;
x *= 2;
}
for(int i = 0; i < 5; ++i) {
e.push_back(cnt & 1);
cnt >>= 1;
}
reverse(e.begin(), e.end());
x -= (int)x;
for(int i = 0; i < 10; ++i) {
x *= 2;
m.push_back((int)x);
x -= (int)x;
}
}
double getval() {
double ans = 1, base = 1;
for(int i = 0; i < 10; ++i) {
base /= 2;
if(m[i]) ans += base;
}
int q = 0, bas = 1;
for(int i = 4; i >= 0; --i) {
if(e[i]) q += bas;
bas <<= 1;
}
q -= 15;
while(q > 0) ans *= 2, --q;
while(q < 0) ans /= 2, ++q;
return ans * (s ? -1 : 1);
}
void print() {
printf("%d", s);
for(int i : e) printf("%d", i);
for(int i : m) printf("%d", i);
printf("\n");
}
};
int main() {
int T = read();
for(int i = 0; i < T; ++i) {
int op = read(); double x1, x2;
scanf("%lf%lf", &x1, &x2);
poi p1 = poi(x1), p2 = poi(x2);
x1 = p1.getval(), x2 = p2.getval();
double ans = x1;
if(op == 2) ans = x1 + x2;
else if(op == 3) ans = x1 * x2;
poi pa = poi(ans);
pa.print();
}
return 0;
}
oj: 牛客
待补
oj: 牛客
待补
oj: 牛客
再回顾一下题意:将数组 a a a 分成若干彼此互不相交的组,每组的异或和为 x x x。求分组的划分数。
思考一个问题:任何异或和为 x x x 的区间都能自成一组吗?
显然不是,例如当 x x x 为 1 1 1 时的2 3 2 3
中的3 2
,虽然异或和为 1 1 1,但如果把3 2
分为一组,两边的2
和3
就无处安放了。正确的分法应该是2 3
和2 3
。
那应该怎么分呢?
考虑将 a a a 从左到右贪心地分成若干个足够小的异或和为x的组,数组内每一个元素都在一个这样的组内。例如当 x x x 为 1 1 1 时, a a a 为1 2 2 1 2 2 1
时,我们将数组分为1
, 2 2 1
, 2 2 1
。
又发现分出的组还可以再分出一些足够小的异或和为0的组,将 a a a 进一步划分为:1
, 2 2
, 1
, 2 2
, 1
。再例如1 2 2 2 2 1
分为1
, 2 2
, 2 2
, 1
。之所以划分出异或和为 0 0 0 的组,是因为当他们出现在两个异或和为 1 1 1 的组之间时,它们既可以合并到左边的组,也可以合并到右边的组,所以他们的数量值得我们关注。
为了方便下文叙述,我们将 异或和为 x x x 的组 称为 u x ux ux,将 异或和为 0 0 0 的组 称为 u 0 u0 u0,将 把数组 a a a 分成若干彼此互不相交的组且每组的异或和为 x x x 的划分数 称为 划分数。
这样分完之后,所有的合理的对数组 a a a 的划分都是 u x ux ux 和 u 0 u0 u0 组合的结果。而且每次必须选奇数个 u x ux ux 合并到一起,不然每个 u x ux ux 的值为 x x x,偶数个 x x x 异或之后为 0 0 0,而不是 x x x。
为了方便进行状态转移,我们在 u x ux ux 中间插入 u 0 u0 u0 的数量,如果不存在 u 0 u0 u0 就插入 0 0 0。我们把这个数组叫做数组 b b b。例如将1 2 2 2 2 1
表示为ux 2 ux
,将1 2 2 1 2 2 1 1
表示为ux 1 ux 1 ux 0 ux
。对于数组两端的 u 0 u0 u0,我们是不考虑的。因为它们只能被合并到相邻的 u x ux ux 而不能单独存在,对答案没有贡献,所以就当它们没有出现过就行了。
然后定义 d p [ i ] dp[i] dp[i] 为 b [ i : ] b[i:] b[i:](从 i i i 到末尾)的划分数。且只考虑 i i i 为偶数的情况( i i i 从 0 0 0 开始计数)之所以不考虑 i i i 为奇数的情况是因为奇数位置对应的都是 u 0 u0 u0 的个数,上面也说了以 u 0 u0 u0 作为数组边界时时可以将其视作不存在,所以 d p [ 偶 数 ] dp[偶数] dp[偶数] 就和 d p [ 偶 数 + 1 ] dp[偶数+1] dp[偶数+1] 一样了,没必要重复计算。
边界:
转移:
综上, d p [ i ] = d p [ i + 4 ] + ( d p [ i + 1 ] + 1 ) ∗ d p [ i + 2 ] dp[i] = dp[i + 4] + (dp[i + 1] + 1) * dp[i + 2] dp[i]=dp[i+4]+(dp[i+1]+1)∗dp[i+2]。
#include
#define rp(i, s, t) for (int i = (s); i <= (t); i++)
#define RP(i, t, s) for (int i = (t); i >= (s); i--)
#define ll long long
using namespace std;
inline int read() {
int s = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * f;
}
const int N = 1e6 + 7;
const ll mod = 1e9 + 7;
int a[N];
int n;
vector<ll> dp;
void solve() {
dp.clear();
n = read();
ll x = read();
rp(i, 1, n) a[i] = read();
int num = 0;
ll tem = 0;
int nu0 = 0;
rp(i, 1, n) {
tem ^= a[i];
if(tem == 0) ++nu0;
else if (tem == x) {
if(num == 0) dp.push_back(0);
else {
dp.push_back(nu0);
dp.push_back(0);
}
nu0 = 0;
tem = 0;
++num;
}
}
if(tem || dp.size() == 0) {
printf("0\n");
return;
}
if(dp.size() == 1) {
printf("1\n");
return;
}
dp[dp.size() - 1] = 1;
dp[dp.size() - 3] = dp[dp.size() - 2] + 1;
for(int i = dp.size() - 5; i >= 0; i -= 2) {
dp[i] = dp[i + 4] + (dp[i + 1] + 1) * dp[i + 2];
dp[i] %= mod;
}
printf("%lld\n", dp[0]);
}
int main() {
solve();
return 0;
}
交题前多测几发真的不浪费时间!!!
交题前多测几发真的不浪费时间!!!
交题前多测几发真的不浪费时间!!!
说不定胡乱写组数据就会发现自己不但过不了,甚至解法都不对。。
K题漫长的debug过程中全靠胡乱造数据发现bug,如果我没有造这么多数据,可能到比赛结束我还在死扣一个错误的解法。