B. Fraction(传送门)
题意
给你两个数组,进行如下运算:
解题思路
直接递归模拟一下就可以了
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define FIN freopen("input.txt", "r", stdin)
#define FOUT freopen("output.txt", "w", stdout)
using namespace std;
typedef pair<int, int> PII;
const int MAXN = 15;
int n;
int A[MAXN], B[MAXN];
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
PII DFS(int x) {
if(x >= n + 1) {
return PII(0, 1);
}
PII v = DFS(x + 1);
int up = v.first;
int down = v.second;
up += A[x] * down;
int nup = down * B[x];
int ndown = up;
int gc = gcd(nup, ndown);
nup /= gc;
ndown /= gc;
return PII(nup, ndown);
}
int main() {
//FIN;
//FOUT;
int _;
int cas = 1;
scanf("%d", &_);
while(_ --) {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d", &A[i]);
}
for(int i = 1; i <= n; i ++) {
scanf("%d", &B[i]);
}
PII p = DFS(1);
printf("Case #%d: %d %d\n", cas ++, p.first, p.second);
}
return 0;
}
D.Triangle(传送门)
题意
给你
1..n
长的棍子,让你去掉这
n
个中的
解题思想
直接二分+DFS暴力,通过题意可以知道,去掉任意x根不能组成三角形,去掉任意
x+1
根一定不能构成三角形,所以这个关系是积性的,所以可以二分,如果我们选了
x
根棍子,然后我们就要针对剩余的
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define FIN freopen("input.txt", "r", stdin)
#define FOUT freopen("output.txt", "w", stdout)
using namespace std;
typedef pair<int, int> PII;
const int MAXN = 20 + 5;
int n;
bool issuc;
int path[MAXN];
int kpath[MAXN];
void DFS(int u, int num, int sz) {
if(sz == num) {
memset(kpath, 0, sizeof(kpath));
for(int i = 0; i < num; i ++) kpath[path[i]] ++;
for(int i = 1; i <= n; i ++) {
if(kpath[i]) continue;
for(int j = i + 1; j <= n; j ++) {
if(kpath[j]) continue;
for(int k = j + 1; k <= n; k ++) {
if(kpath[k]) continue;
if(i + j > k && i + k > j && k + j > i){
return;
}
}
}
}
issuc = true;
return;
}
for(int i = u + 1; i <= n; i ++) {
path[num] = i;
DFS(i, num + 1, sz);
}
}
bool C(int m) {
issuc = false;
DFS(1, 0, m);
return issuc;
}
int main() {
//FIN;
//FOUT;
int _;
int cas = 1;
scanf("%d", &_);
while(_ --) {
scanf("%d", &n);
int lb = -1, ub = n;
while(ub - lb > 1) {
int mid = (ub + lb) >> 1;
if(C(mid)) {
ub = mid;
} else {
lb = mid;
}
}
printf("Case #%d: %d\n",cas ++, ub);
}
return 0;
}
F.Harmonic Value Description(传送门)
题意
给你
1..n
的序列,求它的排列针对下列公式属于第
K
小的序列
解题思路
通过分析我们发现,最小的一定是
∑n−1i=0gcd(pi,pi+1)=n−1
,因为相邻两个数的
gcd(i,i+1)=1
,同时相邻的两个奇数他们的
gcd(oddi,oddi+1)=1
,而相邻的两个偶数
gcd(eveni,eveni+1)=2
,所以我们针对第
1
小的序列直接输出,对于第
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1e6 + 5;
int n, k;
bool vis[MAXN];
int main() {
int _;
int cas = 1;
scanf("%d", &_);
while(_ --) {
scanf("%d%d", &n, &k);
printf("Case #%d:",cas ++);
memset(vis, false, sizeof(vis));
for(int i = 1;i <= k;i ++){
printf(" %d", i * 2);
vis[i * 2] = true;
}
for(int i = 1;i <= k;i ++){
printf(" %d", i * 2 - 1);
vis[i * 2 - 1] = true;
}
for(int i = 1;i <= n;i ++){
if(vis[i]) continue;
printf(" %d", i);
}
printf("\n");
}
return 0;
}
H.Sequence I(传送门)
题意
给你两个序列
解题思路
存暴力不解释
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1e6 + 5;
int n, m, p;
int A[MAXN], B[MAXN];
int main() {
int _;
int cas = 1;
scanf("%d", &_);
while(_ --) {
scanf("%d%d%d", &n, &m, &p);
for(int i = 1; i <= n; i++) {
scanf("%d", &A[i]);
}
for(int i = 1; i <= m; i++) {
scanf("%d", &B[i]);
}
int ans = 0;
for(int i = 1;i <= (n - (m - 1) * p);i ++){
bool flag = true;
for(int j = 0;j < m;j ++){
if(A[i + j * p] != B[j + 1]){
flag = false;
break;
}
}
if(flag) ans ++;
}
printf("Case #%d: %d\n",cas ++, ans);
}
return 0;
}
I.Sequence II(传送门)
题意
解题思路
由于每一次受上一步影响所以无法离线,必须在线,所以想到主席树,然后求一次区间不同数,从后往前建立线段树以确保最新更新的为当前最左边的下标,接着求一下区间第 K 小就可以了
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#define FIN freopen("input.txt", "r", stdin)
using namespace std;
struct CT {
static const int MAXN = 4e5 + 5;
static const int TIME = 20;
int tot;
int T[MAXN * TIME], LT[MAXN * TIME], RT[MAXN * TIME], SUM[MAXN * TIME];
void T_init() {
tot = 0;
}
void build(int &o, int l, int r) {
o = ++ tot;
SUM[o] = 0;
if(l == r) return;
int mid = (l + r) >> 1;
build(LT[o], l, mid);
build(RT[o], mid + 1, r);
}
void update(int &o, int l, int r, int last, int p, int v) {
o = ++ tot;
LT[o] = LT[last];
RT[o] = RT[last];
SUM[o] = SUM[last] + v;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(LT[o], l, mid, LT[last], p, v);
else update(RT[o], mid + 1, r, RT[last], p, v);
}
int query_sum(int nl, int pos, int l, int r) {
if(l == r) return SUM[nl];
int mid = (l + r) >> 1;
if(pos <= mid) return query_sum(LT[nl], pos, l, mid);
else return query_sum(RT[nl], pos, mid + 1, r) + SUM[LT[nl]];
}
int query_pos(int lt, int k, int l, int r) {
if(l == r) return l;
int mid = (l + r) >> 1;
if(k <= SUM[LT[lt]]) return query_pos(LT[lt], k, l, mid);
else return query_pos(RT[lt], k - SUM[LT[lt]], mid + 1, r);
}
} ST;
int n, m;
int A[CT::MAXN], B[CT::MAXN];
map<int,int>MP;
int main() {
//FIN;
int _;
int cas = 1;
scanf("%d", &_);
while(_ --) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) {
scanf("%d", &A[i]);
}
MP.clear();
ST.T_init();
ST.build(ST.T[n + 1], 1, n);
for(int i = n; i >= 1; i --) {
if(!MP[A[i]]) {
ST.update(ST.T[i], 1, n, ST.T[i + 1], i, 1);
} else {
ST.update(ST.T[i], 1, n, ST.T[i + 1], MP[A[i]], -1);
ST.update(ST.T[i], 1, n, ST.T[i], i, 1);
}
MP[A[i]] = i;
}
int a, b;
int ans = 0;
printf("Case #%d:", cas ++);
while(m --) {
scanf("%d%d", &a, &b);
int na = (a + ans) % n + 1, nb = (b + ans) % n + 1;
a = min(na, nb);
b = max(na, nb);
int tmp = ST.query_sum(ST.T[a], b, 1, n);//求区间不同数个数
tmp = tmp + 1 >> 1;
ans = ST.query_pos(ST.T[a], tmp, 1, n);//求区间第K小
printf(" %d", ans);
}
printf("\n");
}
return 0;
}
J.Ugly Problem(传送门)
题意
给定一个长度最多为
解题思路
总体思路
每次都拆分出最大的回文数字即可
个人思路
对于求解最大回文字符串步骤
1 对于当前数的位长为奇数,那么从中间拆开分为左边一半右边一半,分情况讨论:左边大于等于右边和左边小于右边
2 对于当前数的位长为偶数,也是和奇数一样处理就可以了
当时几乎写了一个大数,好尴尬Orz
代码
#include <cstdio>
#include <vector>
#include <string>
#include <iostream>
#include <cstring>
#include <algorithm>
//#include <windows.h>
#define FIN freopen("input.txt", "r", stdin)
#define FOUT freopen("output.txt", "w", stdout)
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
struct StringNum {
static const int MAXN = 1e3 + 5;
static const int INF = 1e5;
char S[MAXN];
int len;
StringNum() {
len = 0;
memset(S, 0, sizeof(S));
S[len ++] = '0';
S[len] = '\0';
}
StringNum(const StringNum &sn) {
*this = sn;
}
StringNum(bool sflag, int slen) {
for(int i = 0; i < slen; i ++) {
S[i] = '0';
}
S[slen] = '1';
S[len = slen + 1] = '\0';
}
StringNum(int p) {
int slen = 0;
while(p) {
S[slen ++] = p % 10 + '0';
p /= 10;
}
if(slen == 0) S[slen ++] = '0';
S[len = slen] = '\0';
}
StringNum(char buf[]) {
int slen = strlen(buf);
for(int i = 0; i < slen; i ++) {
S[i] = buf[i];
}
S[len = slen] = '\0';
}
void read() {
cin >> S;
len = strlen(S);
*this = this -> reverse();
}
StringNum substr(int l, int slen) {
StringNum sn;
for(int i = l; i < l + slen && i < len; i ++) {
sn.S[i - l] = S[i];
}
sn.len = slen;
sn.S[slen] = '\0';
if(sn.len == 0){
sn.S[sn.len ++] = '0';
sn.S[sn.len] = '\0';
}
return sn;
}
StringNum reverse() {
StringNum sn = *this;
for(int i = 0; i < len / 2; i ++) {
swap(sn.S[i], sn.S[len - 1 - i]);
}
return sn;
}
StringNum operator = (const StringNum &p) {
for(int i = 0; i < p.len; i ++) {
S[i] = p.S[i];
}
S[len = p.len] = '\0';
}
StringNum operator - (const StringNum &p) {
StringNum tmp = *this;
int jw = 0;
for(int i = 0; i < len; i ++) {
char pz = '0';
if(i < p.len) pz = p.S[i];
if(tmp.S[i] + jw < pz) {
tmp.S[i] = tmp.S[i] + 10;
tmp.S[i] = tmp.S[i] - pz + '0' + jw;
jw = -1;
} else {
tmp.S[i] = tmp.S[i] - pz + '0' + jw;
jw = 0;
}
}
while(tmp.S[tmp.len - 1] == '0' && tmp.len > 0) tmp.S[-- tmp.len] = '\0';
if(tmp.len <= 0){
tmp.S[tmp.len ++] = '0';
tmp.S[tmp.len] = '\0';
}
return tmp;
}
bool operator > (const StringNum &p) const {
if(len > p.len) return true;
if(len < p.len) return false;
for(int i = len - 1; i >= 0; i --) {
if(S[i] > p.S[i]) return true;
}
return false;
}
bool operator > (const int &intp) const {
StringNum p(intp);
return *this > p;
}
bool operator < (const StringNum &p) const {
if(len > p.len) return false;
if(len < p.len) return true;
for(int i = len - 1; i >= 0; i --) {
if(S[i] < p.S[i]) return true;
}
return false;
}
bool operator < (const int &intp) const {
StringNum p(intp);
return *this < p;
}
};
char tmpS[StringNum::MAXN];
vector<string>ve;
StringNum o_L_l_R(StringNum sna) {//处理奇数左边小于右边
if(sna.len == 1) return sna;
StringNum a = sna.substr(sna.len / 2 + 1, sna.len / 2);
a = a.reverse();
StringNum b = sna.substr(0, sna.len / 2);
int l = 0;
for(int i = 0; i < a.len; i ++) {
tmpS[l ++] = a.S[i];
}
tmpS[l ++] = sna.S[sna.len / 2];
for(int i = a.len - 1; i >= 0; i --) {
tmpS[l ++] = a.S[i];
}
tmpS[l] = '\0';
a = StringNum(tmpS);
//printf("[%s]\n", a.S);
return a;
}
StringNum e_L_l_R(StringNum sna) {//处理偶数左边小于右边
if(sna.len == 1) return sna;
StringNum a = sna.substr(sna.len / 2, sna.len / 2);
a = a.reverse();
int l = 0;
for(int i = 0; i < a.len; i ++) {
tmpS[l ++] = a.S[i];
}
for(int i = a.len - 1; i >= 0; i --) {
tmpS[l ++] = a.S[i];
}
tmpS[l] = '\0';
a = StringNum(tmpS);
return a;
}
StringNum o_L_g_R(StringNum sna) {//处理奇数左边大于右边
StringNum tmpb = sna - sna.substr(0, sna.len / 2) - StringNum(1);
if(tmpb.len & 1){
tmpb = o_L_l_R(tmpb);
}
else{
tmpb = e_L_l_R(tmpb);
}
//printf("[%s]\n", tmpb.S);
return tmpb;
}
StringNum e_L_g_R(StringNum sna) {//处理偶数左边大于右边
StringNum tmpb = sna - sna.substr(0, sna.len / 2) - StringNum(1);
if(tmpb.len & 1){
tmpb = o_L_l_R(tmpb);
}
else{
tmpb = e_L_l_R(tmpb);
}
//printf("[%s]\n", tmpb.S);
return tmpb;
}
int main() {
//FIN;
//FOUT;
ios::sync_with_stdio(false);
int _;
int cas = 1;
cin >> _;
StringNum sna;
while(_ --) {
ve.clear();
sna.read();
while(sna > 0) {
StringNum a = sna.substr(sna.len / 2 + (sna.len & 1), sna.len / 2);
a = a.reverse();
StringNum b = sna.substr(0, sna.len / 2);
StringNum tmpt;
if((sna.len & 1) && sna.len > 1) {
if(!(a > b)) {
tmpt = o_L_l_R(sna);
sna = sna - tmpt;
} else {
tmpt = o_L_g_R(sna);
sna = sna - tmpt;
}
ve.push_back(string(tmpt.S));
} else if(!(sna.len & 1) && sna.len > 1) {
if(!(a > b)) {
tmpt = e_L_l_R(sna);
sna = sna - tmpt;
} else {
tmpt = e_L_g_R(sna);
sna = sna - tmpt;
}
ve.push_back(string(tmpt.S));
} else {
ve.push_back(string(sna.S));
sna = sna - sna;
}
//Sleep(1000);
}
cout << "Case #" << cas ++ <<":"<<"\n";
cout << ve.size() << endl;
for(int i = 0; i < ve.size(); i ++) {
cout << ve[i] << endl;
}
}
return 0;
}
/*
以下是一些思路和数据
odd > 1:
l <= r
result:lzl
cur -= lzl
odd == 1:
result:cur
l > r
result:l(z-1)l
cur -= l(z-1)l
even:
l <= r
result:ll
cur -= ll
odd==1:
result:cur
l > r
result:l-1l-1
cur -= l-1l-1
*/
//1845481
//18455481
//1345321
//1845241
//1425241
//1000
//999+1