重点回忆下我觉得比较有意义的题目吧。水题就只贴代码了。

Distinct Characters Subsequence

水。

代码:

 #include <cstdio>
#include <iostream>
#include <map>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#define pb push_back
#define mp make_pair
#define esp 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pb push_back
#define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x7f7f7f7f
using namespace std;
typedef long long LL;
typedef map<int, int> MPS;
typedef pair<int, int> PII; const int maxn = (int)1e5 + ;
char s[maxn];
int vis[]; int main(){ int n;
for(int i = scanf("%d", &n); i <= n; i++){
memset(vis, , sizeof vis);
scanf("%s", s);
int len = ;
for(int i = ; s[i]; i++) if(!vis[s[i]-'a']){
vis[s[i]-'a'] = ;
len++;
}
cout << len << endl;
}
return ;
}

Let us construct palindrome

题意:给定一个字符串问能否删除一个字符之后剩下的字符连接起来构成回文串。

分析:可以从两端开始枚举,直到遇到第一对不相匹配的字符(如果完全匹配答案肯定是YES),然后考虑这对字符中去掉一个,两种情况下分别继续配对,看最后能不能形成回文串。

代码:

 #include <cstdio>
#include <iostream>
#include <map>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#define pb push_back
#define mp make_pair
#define esp 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pb push_back
#define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x7f7f7f7f
using namespace std;
typedef long long LL;
typedef map<int, int> MPS;
typedef pair<int, int> PII; const int maxn = (int)1e5 + ;
char s[maxn]; int main() { int T;
for(int t = scanf("%d", &T); t <= T; t++) {
scanf("%s", s);
int len = strlen(s);
int i = , j = len-;
int ok = ;
while(i < j) {
if(s[i] != s[j]) {
ok = ;
break;
}
i++, j--;
}
if(ok) puts("YES");
else {
if(i == j-) {
puts("YES");
continue;
} else {
int ii = i, jj = j;
if(s[i] == s[j-]) {
j--;
ok = ;
while(i < j) {
if(s[i] != s[j]) {
ok = ;
break;
}
i++, j--;
}
if(ok) {
puts("YES");
continue;
}
}
i = ii, j = jj;
if(s[i+] == s[j]) {
i++;
ok = ;
while(i < j) {
if(s[i] != s[j]) {
ok = ;
break;
}
i++, j--;
}
if(ok) {
puts("YES");
continue;
}
}
puts("NO");
}
}
}
return ;
}

Chef and Segment Game

题意:给定[0, X]的线段,然后首先切1次分成2等分,切2次将两份等分成4分,然后切4分,求第k次切下去时的x坐标。

分析:先考虑是位于2^i变2^i+1的等分过程中,然后再求是将2^i等分成2^i+1时第几次切下去。

代码:

 #include <cstdio>
#include <iostream>
#include <map>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#define pb push_back
#define mp make_pair
#define esp 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pb push_back
#define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x7f7f7f7f
using namespace std;
typedef long long LL;
typedef map<int, int> MPS;
typedef pair<int, int> PII; const int maxn = ;
int dig[maxn];
int getDig(LL x) {
int len = ;
while(x) {
dig[len++] = x&;
x >>= ;
}
return len;
}
int main() { int T;
for(int t = scanf("%d", &T); t <= T; t++) {
double x;
LL k;
scanf("%lf%lld", &x, &k);
int len = getDig(k);
int ok = ;
for(int i = ; i < len; i++) if(dig[i] == ) {
ok = ;
break;
}
if(ok) {
printf("%.10f\n", x-1.0/pow(2.0,len)*x);
} else {
printf("%.10f\n", 1.0*x*((1.0*k-((1LL<<(len-))-1.0))/pow(2.0, len-)-1.0/pow(2.0, len)));
}
}
return ;
}

Chef and Red Black Tree

题意:一棵无限深度的二叉树,每个结点一个颜色,(红或黑)树上相邻两点颜色不同,根节点颜色初始为黑色,编号为1,任意结点u的两个左右儿子编号为2*u, 2*u+1, 每次3种操作:

Qi x 翻转x的颜色;

Qr x y 询问x到y路径上红色结点的颜色;

Qb x y询问x到y路径上黑色结点的颜色。

分析:将x到y结点上相应结点个数变成求一个点到根节点上相应颜色的结点的个数,然后再减去重复路径上的。由于相邻结点颜色不同,因此,一个点到根节点上相应颜色结点个数就是l/2+1(如果该节点与根节点同色且l为奇数)

代码:

 #include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define esp 1e-8
#define lowbit(x) ((x)&(-x))
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pb push_back
#define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x0f0f7f7f
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef map<int, LL> MPS;
int getDig(int x){
int len = ;
while(x){
len++;
x >>= ;
}
return len;
}
int main(){ int q;
scanf("%d", &q);
char s[];
int rt = ;
while(q--){
scanf("%s", s);
if(s[] == 'i'){
rt ^= ;
}
else {
int x, y, lx, ly;
scanf("%d%d", &x, &y);
// cout << x << ' ' << y << endl;
lx = getDig(x);
ly = getDig(y);
int col = s[] == 'r';
int ans = (lx+(col == rt))/ + (ly+(col == rt))/;
if(lx > ly){
while(lx != ly) x >>= , lx--;
}else{
while(lx != ly) y >>= , ly--;
}
while(x != y) x >>= , y >>= ;
lx = getDig(x);
ans -= (lx + (col == rt))/*;
ans += (col == rt ? lx& : !(lx&));
cout << ans << endl;
} }
return ;
}

 

 

Fombinatorial

题意:定义f(i) = 1^1*2^2*3^3......i^i,求g(r) = f(n)/(f(r)*f(n-r)) mod(m)保证g(r)结果为整数。

分析:

m不一定为质数,所以题目就不能直接利用逆元了,因为逆元的前提是两个数互质,这里f(r),f(n-r)不一定互质,所以我们关键就是在于把f(r)与m互质,将f(r)和f(n-r)中包含的m的质因子全部提取出来,剩下来的一定就互质了,利用逆元处理,然后乘上质因子部分。

代码:

 #include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define esp 1e-12
#define lowbit(x) ((x)&(-x))
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pb push_back
#define pf(x) ((x)*(x)) #define pi acos(-1.0) #define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x0f0f0f0f
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = (int)1e5 + ;
int N, M, Q; LL f[maxn], ppow[maxn];
int phi; inline LL powmod(LL a, LL b, LL c) {
LL res = ;
while(b) {
if(b&) res = res*a%c;
a = a*a%c;
b >>= ;
}
return res;
} inline LL getNum(int x, int p) {
LL t = p;
LL res = ;
while(t <= (LL)x) {
int tmp = x/t;
res += (LL)(tmp+)*tmp/*t;
t *= p;
}
return res;
}
vector<int> primes; bool isPrime(int x) {
for(int i = ; i < sz(primes); i++)
if(x%primes[i] == ) return false;
return true;
}
void init() {
for(int i = ; i < ; i++)
if(isPrime(i)) primes.pb(i);
}
void getFac(int m, vector<int> &pfac) {
pfac.clear();
phi = m;
for(int i = ; i < sz(primes) && m/primes[i] >= primes[i]; i++) {
if(m%primes[i] == ) {
phi -= phi/primes[i];
pfac.pb(primes[i]);
while(m%primes[i] == )
m /= primes[i];
}
}
if(m != ) {
pfac.pb(m);
phi -= phi/m;
}
} int main() {
// in
cin.sync_with_stdio();
cout.setf(ios::fixed, ios::floatfield);
cout.precision();
int T;
init();
vector<int> pfac; for(int t = scanf("%d", &T); t <= T; t++) {
scanf("%d%d%d", &N, &M, &Q);
pfac.clear();
getFac(M, pfac);
f[] = %M; for(int i = ; i <= N; i++) {
int x = i;
for(int j = ; j < sz(pfac) && x >= pfac[j]; j++) {
if(x % pfac[j] == ) {
while(x%pfac[j] == )
x /= pfac[j];
}
}
f[i] = f[i-]*powmod(x, i, M)%M;
}
while(Q--) {
int r;
scanf("%d", &r);
if(M == )
printf("0\n");
else {
int res = f[N];
res = 1LL*res*powmod(f[r], phi-, M)%M*powmod(f[N-r], phi-, M)%M;
for(int i = ; i < sz(pfac) && pfac[i] <= N; i++) {
LL num = getNum(N, pfac[i])-getNum(r, pfac[i])-getNum(N-r, pfac[i]);
res = 1LL*res*powmod(pfac[i], num, M)%M;
}
printf("%d\n", res);
}
}
}
return ;
}

当然还可以用线段树预处理所有可能的答案啦,因为g(r) = n^n*(n-1)^(n-1)*.....(n-r+1)/(r^r*(r-1)^(r-1)*....2^2*1^1)。

每次处理完g(r)之后处理,下一个答案时,相当于乘以(n-r)^(n-r)/(r+1)^(r+1),我们对分子分母处理一下所含质因子的幂次,更新线段树。

代码:

 #include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define esp 1e-12
#define lowbit(x) ((x)&(-x))
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1 #define sz(x) ((int)((x).size()))
#define pb push_back
#define pf(x) ((x)*(x)) #define pi acos(-1.0) #define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x0f0f0f0f
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = (int)1e5 + ;
int cnt[maxn], pa[maxn], vis[maxn], id[maxn];
int num;
vector<int> primes; LL powmod(LL a, LL b, LL c) {
LL res = ;
while(b > ) {
if(b&) res = res*a%c;
a = a*a%c;
b >>= ;
}
return res;
} class SegmentTree {
private:
vector<LL>power;
vector<int> tree;
int mod;
public:
SegmentTree(int n, int m) {
mod = m;
n = lower_bound(primes.begin(), primes.end(), n)-primes.begin();
n++;
power.resize(n, );
tree.resize(n*, %m);
}
void update(int pos, LL c) {
power[pos] += c;
update(, sz(power)-, , pos, powmod(primes[pos], power[pos], mod));
}
void update(int l, int r, int rt, int pos, int c) {
if(l == r) {
tree[rt] = c;
return;
}
int m = (l+r)>>;
if(pos <= m)
update(lson, pos, c);
else update(rson, pos, c);
tree[rt] = 1LL*tree[rt<<]*tree[rt<<|]%mod;
}
int val() {
return tree[];
}
};
void pre() {
memset(id, 0x0f, sizeof id);
id[] = maxn;
cnt[] = ;
pa[] = ;
num = ; for(int i = ; i < maxn; i++) if(!vis[i]) {
cnt[i] = ;
pa[i] = ;
id[i] = num;
primes.pb(i);
for(int j = i*; j < maxn; j += i) {
if(vis[j]) continue;
vis[j] = ;
id[j] = num; if(id[j/i] == num) {
pa[j] = pa[j/i];
cnt[j] = cnt[j/i] + ;
} else {
pa[j] = j/i;
cnt[j] = ;
}
}
num++;
}
// bug(pa[4])
}
int n, m, q;
int ans[maxn]; int main() { int T;
pre();
// bug(1)
for(int t = scanf("%d", &T); t <= T; t++) {
scanf("%d%d%d", &n, &m, &q);
SegmentTree tree(n ,m);
for(int i = ; i <= n/; i++) {
int p = n-i+, q = i; while(p != || q != ) {
int x = id[p];
// bug(i)
int y = id[q];
LL ct = ;
x = min(x, y);
if(x == id[p]) {
ct += 1LL*cnt[p]*(n-i+);
p = pa[p];
}
if(x == id[q]) {
ct -= 1LL*cnt[q]*i;
q = pa[q];
}
// cout << p << q << endl;
tree.update(x, ct);
}
ans[i] = tree.val();
}
while(q--) {
int r;
scanf("%d", &r);
r = min(r, n-r);
printf("%d\n", ans[r]);
}
}
return ;
}

 

Chef and Churu

题意:和区间询问有关,不过每次询问的一系列区间的和。简单来说就是这样,给定n个函数,每个函数询问Li到Ri的区间内数的和。有2中操作,操作1改变某个数的值,操作2询问函数m到n的和。

分析:询问一系列区间的和,可以分块处理,将函数分成L块, L = sqrt(n),每一块的大小也是L。预处理每块内的函数所包含的每个元素的次数,算出初始时该块内函数的和,每次更新数的值时,只需要针对每个块内该元素包含的次数进行更新。询问时,包含的整块函数值的和直接加到结果中,对于不完全包含的函数块,只能查询相应区间的和了,这里似乎只能用树状数组进行更新查询,线段树常数过大会TLE。

代码:

 #include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define esp 1e-12
#define lowbit(x) ((x)&(-x))
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pb push_back
#define pf(x) ((x)*(x)) #define pi acos(-1.0) #define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x0f0f0f0f
using namespace std;
typedef unsigned long long LL;
typedef pair<int, int> PII;
const int maxn = (int)1e5 + ;
const int maxm = ; PII func[maxn];
int a[maxn], cnt[maxm][maxn], num[maxm][maxn];
LL ans[maxm], sum[maxn]; int L, n, q; void add(int x, int c) {
while(x <= n) {
sum[x] += c;
x += lowbit(x);
}
}
void update(int x, int c){
add(x, c-a[x]);
a[x] = c;
}
LL query(int x) {
LL res = ;
while(x > ) {
res += sum[x];
x -= lowbit(x);
}
return res;
}
LL query(int l, int r){
return query(r)-query(l-);
}
void build(){
for(int i = ; i <= n; i++){
add(i, a[i]);
}
}
void pre() {
build();
for(int i = ; i < L; i++) {
for(int j = ; j <= n; j++) {
num[i][j] = num[i][j-] + cnt[i][j];
ans[i] += 1ULL*num[i][j]*a[j];
}
}
}
int main() { scanf("%d", &n);
L = (int)sqrt(n) + ;
for(int i = ; i <= n; i++)
scanf("%d", a+i);
for(int i = ; i < n; i++) {
int l, r;
scanf("%d%d", &l, &r);
func[i] = PII(l, r);
cnt[i/L][l]++;
cnt[i/L][r+]--;
}
pre();
scanf("%d", &q);
while(q--) {
int type;
int l, r;
scanf("%d%d%d", &type, &l, &r);
if(type == ) {
for(int i = ; i < L; i++) {
ans[i] += 1ULL*num[i][l]*(r-a[l]);
}
update(l, r);
} else {
l--, r--;
int x = l/L;
int y = r/L;
LL res = ;
if(x == y && y-x+ != L) {
while(l <= r) {
res += query(func[l].first, func[l].second);
l++;
}
} else {
int ll = (l%L ? x+ : x);
int rr = ((r+)%L ? y- : y);
for(int i = ll; i <= rr; i++)
res += ans[i];
while(l%L) {
res += query(func[l].first, func[l].second);
l++;
}
while((r+)%L) {
res += query(func[r].first, func[r].second);
r--;
}
}
printf("%llu\n", res);
}
}
return ;
}

 

题意:

Sereja and Permutations

题意:

一个排列p,每次去掉其中一个元素,然后将剩下的数中,所有大于去掉元素的数减1,这样可以得到一个n-1的排列,进行n次可以得到q[1],q[2],........q[n].

现在任意顺序给定n个排列表示q[i],求原来排列p。

分析:显然是一个简单问题的逆问题,但似乎也不是很难做诶,考虑任意给定的一个q,由于不知道他是去掉哪个数后得到的,也不知道去掉的数的位置,所以枚举共有n^2种情况,然后检测得到的p‘是不是满足条件的,也就是做一遍原来的操作,能否得到对应的q,由于q[i]可能有重复,所以要记录得到的个数,最后要求不同的q的个数对应相等。

代码:

 #include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define esp 1e-12
#define lowbit(x) ((x)&(-x))
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1 #define sz(x) ((int)((x).size()))
#define pb push_back
#define pf(x) ((x)*(x)) #define pi acos(-1.0) #define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x0f0f0f0f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef map<ULL, int> MPS; const int maxn = ;
const int B = ; int a[maxn][maxn];
int num[maxn], ct[maxn]; MPS mps;
int cnt; int id(ULL x) {
return mps[x];
}
int ID(ULL x) {
if(mps.count(x) == false) {
mps[x] = cnt++;
}
num[mps[x]]++;
return mps[x];
}
int main() { int T;
for(int t = scanf("%d", &T); t <= T; t++) {
int n;
scanf("%d", &n);
cnt = ;
memset(num, , sizeof num);
mps.clear();
for(int i = ; i <= n; i++) {
ULL Hash = ;
for(int j = ; j < n; j++) {
scanf("%d", &a[i][j]);
Hash = Hash*B + a[i][j];
}
ID(Hash);
}
int ok = ; for(int i = ; i <= n; i++) {
for(int j = ; j <= n; j++) {
vector<int> vec;
for(int k = ; k < n; k++) {
int x = a[][k];
if(x >= i) x++;
if(j == k)
vec.pb(i);
vec.pb(x);
}
if(j == n) vec.pb(i);
ok = ;
memset(ct, , sizeof ct);
for(int k = ; k < n; k++) {
ULL ha = ;
for(int kk = ; kk < n; kk++) {
if(kk == k) continue;
int x = vec[kk];
if(x > vec[k]) x--;
ha = ha*B + x;
}
if(mps.count(ha) == false) {
ok = ;
break;
}
ct[id(ha)]++;
}
if(!ok) continue;
for(int k = ; k < cnt; k++) {
if(num[k] != ct[k]) {
ok = ;
break;
}
}
if(ok) {
for(int k = ; k < sz(vec); k++)
printf("%d%c", vec[k], k == sz(vec)- ? '\n' : ' ');
break;
}
}
if(ok) break;
}
}
return ;
}

Chef and Words

题意:给定一个字符串,然后是一个矩阵表示字符i变成j的概率是a[i][j]最后一些字符串。每次每个字符都会变化一次,k次后,由原始字符串变成其中一个目标字符串的概率.

分析:先预处理一下i经过k步变成j的概率pi,j,考虑原始串变成目标串的概率,就是各个位置的字符i经过k次后变成目标串对应位置字符j的概率pi, j的乘积,而最终答案就是变成各个不同目标串的概率的和。

 #include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define esp 1e-8
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pb push_back
#define in freopen("solve_in.txt", "r", stdin);
#define out freopen("solve_out.txt", "w", stdout); #define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x7f7f7f7f
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef map<string, int> MPS;
typedef long double LD;
MPS mps;
const int maxn = ; struct Matrix {
int n, m;
double a[maxn][maxn];
Matrix() {}
Matrix(int n, int m):n(n), m(m) {
memset(a, , sizeof a);
}
};
double p[maxn][maxn];
vector<string> word;
int n, k;
char str[];
char tmp[];
int cnt;
Matrix operator * (Matrix &a, Matrix &b) {
Matrix c;
c.n = a.n;
c.m = b.m;
for(int i = ; i < c.n; i++) for(int j = ; j < c.m; j++) {
c.a[i][j] = 0.0;
for(int k = ; k < a.m; k++)
c.a[i][j] += a.a[i][k]*b.a[k][j];
// cout << c.a[i][j] << endl;
// if(fabs(c.a[i][j]) < 1e-8)
// c.a[i][j] = 0.0;
}
return c;
}
bool idx(string str) {
if(mps.count(str) == false) {
mps[str] = ++cnt;
return true;
}
return false;
}
int ID(char ch) {
return ch - 'a';
} int main() { int T;
Matrix E0(, );
for(int i = ; i < maxn; i++)
for(int j = ; j < maxn; j++) E0.a[i][j] = i == j ? 1.0 : 0.0; for(int t = scanf("%d", &T); t <= T; t++) {
mps.clear();
word.clear();
cnt = ;
scanf("%d%d", &n, &k);
scanf("%s", str);
int len = strlen(str);
for(int i = ; i < ; i++) for(int j = ; j < ; j++)
scanf("%lf", &p[i][j]);
// cin >> p[i][j]; for(int i = ; i < n; i++) {
scanf("%s", tmp);
if(strlen(tmp) != len) continue;
if(idx(tmp)) {
word.pb(tmp);
}
}
Matrix res = E0, c(, ); for(int i = ; i < ; i++) for(int j = ; j < ; j++)
c.a[i][j] = p[j][i];
// cout << k << endl;
while(k) {
if(k&) res = res*c;
c = c*c;
k >>= ;
}
// for(int i = 0; i < 26; i++) for(int j = 0; j < 26; j++)
// memset(clap, 0, sizeof clap);
// for(int i = 0; i < 26; i++)
// for(int j = 0; j < 26; j++)
// clap[i] += res.a[j][i];
double ans = .;
for(int i = ; i < sz(word); i++) {
// cout << word[i] << endl;
double tt = 1.0;
for(int j = ; j < len; j++) {
int u = ID(str[j]);
int v = ID(word[i][j]);
// cout << res.a[v][u] << endl;
tt *= res.a[v][u];
}
ans += tt;
} printf("%.10f\n", ans);
}
return ;
}

 

04-14 19:26