[20151017]SCZ训练

suffix

给定一个单词,如果该单词以 er、ly 或者 ing 后缀结尾,则删除该后缀(题目保证删除后缀后的单词长度不为 0),否则不进行任何操作。
Input
输入一行,包含一个单词(单词中间没有空格,每个单词最大长度为 32)
Output
输出按照题目要求处理后的单词。
Scoring
• 对于 40% 的数据,单词最大长度不超过 5。
Solution :
No need for Solution.
Code :

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; i++)
char st[50];
int main(){
        scanf("%s", st);
        int len = strlen(st);
        if (st[len - 2] == 'e' && st[len - 1] == 'r'){
                rep(i, 0, len - 3) printf("%c", st[i]); printf("\n");
        }else if (st[len - 2] == 'l' && st[len - 1] == 'y'){
                rep(i, 0, len - 3) printf("%c", st[i]); printf("\n");
        }else if (st[len - 3] == 'i' && st[len - 2] == 'n' && st[len - 1] == 'g'){
                rep(i, 0, len - 4) printf("%c", st[i]); printf("\n");
        }else printf("%s\n", st);
        return 0;
}

weight

设有 1g, 2g, 3g, 5g, 10g, 20g 的砝码各若干枚(其总重 ≤ 100, 000),要求:计算用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况。
Input
,a1,a2,a3,a4,a5,a6,1ga1,2ga2,......,20ga6
Output
以“Total=N”的形式输出,其中 N 为可以称出的不同重量的个数。
Scoring
• 对于 20% 的数据,砝码总个数不超过 20。
• 对于 40% 的数据,砝码总个数不超过 800。
Solution :
多重背包。二进制拆分优化+bitset大法。
Code :

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; i++)
const int N = 111111;
int w[6] = {1, 2, 3, 5, 10, 20};
int cnt, a[N << 1], lst[N << 1]; 
bitset<N> ans;
int main(){
        rep(i, 0, 5) scanf("%d", &a[i]);
        cnt = 0;
        rep(i, 0, 5){
                int p = 1;
                while (a[i] >= p){
                    lst[++cnt] = p * w[i]; a[i] -= p; p <<= 1;
                }
                if (a[i] > 0) lst[++cnt] = a[i] * w[i];
        }

        ans[0] = 1;
        rep(i, 1, cnt) ans |= (ans << lst[i]);
        printf("Total=%d\n", ans.count() - 1);
        return 0;
}

hopscotch

给定一个 n 行 m 列的方格,每个格子里有一个正整数 a,1 ≤ a ≤ k, k ≤ n ∗ m
假设你当前时刻站在 (i, j) 这个格子里,你想要移动到 (x, y),那必须满足以下三个条件
1:i < x
2:j < y
3:第 i 行第 j 列格子里的数不等于第 x 行第 y 列格子里的数
求从 (1, 1) 移动到 (n, m) 的不同的方案数
Input
第一行三个数 n, m, k
接下来 n 行每行 m 个正整数,表示每个格子里的数
Output
一行一个数,表示从 (1, 1) 移动到 (n, m) 的不同的方案数,模 10^9 + 7
Scoring
• 对于 20% 的数据,n, m ≤ 20。
• 对于 60% 的数据,n, m ≤ 100。
• 对于 100% 的数据,n, m ≤ 750。
Solution :
dp方程容易得到,是一个n^4的东西。我们考虑补集,统计一个点左上角和它相同的dp值的和。
一个显而易见的想法是开权值范围*图大小的二维BIT,然而MLE。
于是我们转向线段树,我们可持久化之,动态开节点,这样不会MLE了。
Code :
暂无

alphabet

给定一棵 n 个点的树,树上每个节点代表一个小写字母,询问一个字符串 S 是否在树上出现过?
字符串 S 出现过即表示存在两个点 u, v,u 到 v 的最短路径上依次连接所有点上的字母恰好是 S
Input
第一行一个数 T 表示数据组数
每组数据先输入一个数 n 表示这棵树有 n 个节点
接下来 n − 1 行每行两个数 u, v,表示 u, v 之间存在一条无向边
下一行包含 n 个字符,表示每个节点上的字符
下一行包含一个字符串 S
Output
对于每组数据”Case #k: ”,k 为测试点编号,如果出现过则输出 Find,否则输出Impossible
Scoring
• 对于 20% 的数据,N ≤ 1000。
• 对于另外 20% 的数据,N ≤ 10 4 ,且树上有且仅有一种字母。
• 对于另外 30% 的数据,N ≤ 10 4 ,且树随机生成。
• 对于另外 30% 的数据,N ≤ 10 4 ,且树上的字母随机生成。
Solution :
点分治+树哈希
Code :

/************************************************************************* > File Name: alphabet.cpp > Author: Archer ************************************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;

typedef long long ll;
typedef unsigned int UI;
typedef pair<int, int> PII;
typedef vector<UI>::iterator VIT;
const int N = 11111;
const UI SEED = 131;
#define REP(i, l, r) for (int i = l; i <= r; i++)
#define PER(i, r, l) for (int i = r; i >= l; i--)
#define MP make_pair
#define PB push_back
#define MS(_) memset(_, 0, sizeof(_))
struct Node{int v; Node *nxt;}pool[N << 5], *tail = pool, *g[N];
UI h1[N], h2[N];
int q[N], sz[N], f[N], fa[N], n;
bool vis[N];
char st[N], w[N];
vector<UI> v;
__gnu_pbds::gp_hash_table<UI, UI> goal1, goal2;
__gnu_pbds::gp_hash_table<UI, bool> h ;

inline void ckmax(int &a, int b){ if (a < b) a = b; }
inline void ckmax(PII &a, PII b){ if (a < b) a = b; }
inline void setIO(){
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
}
inline void addedge(int u, int v){
    tail->v = v; tail->nxt = g[u]; g[u] = tail++;
    tail->v = u; tail->nxt = g[v]; g[v] = tail++;
}
inline UI calgoal(char *str){ MS(h1); MS(h2); goal1.clear(); goal2.clear();
    UI hash = 0, base = 1;  
    PER(i, strlen(str) - 1, 0) h2[i] = (hash += base * (st[i])), base *= SEED;
    hash = 0; base = 1;
    REP(i, 0, strlen(str) - 1) h1[i] = (hash += base * (st[i])), base *= SEED;
    REP(i, 0, strlen(str) - 1) goal1[h1[i]] = h2[i], goal2[h2[i]] = h1[i];
}
inline int getrt(int x){ int l, r, now;
    for (q[l = r = 1] = x; l <= r; l++){
        sz[now = q[l]] = 1; f[now] = 0; 
        for (Node *p = g[now]; p; p = p->nxt)
            if (!vis[p->v] && p->v != fa[now]) fa[q[++r] = p->v] = now; 
    }
    PER(i, r, 1) sz[fa[q[i]]] += sz[q[i]];
    PER(i, r, 1){
        ckmax(f[q[i]], sz[x] - sz[q[i]]); ckmax(f[fa[q[i]]], sz[q[i]]);
        if (f[q[i]] <= sz[x] / 2) return q[i]; 
    }
}
inline void getans(int x, int fa,  UI cur){
    cur = cur * SEED + w[x]; v.PB(cur);
    for (Node *p = g[x]; p; p = p->nxt) 
        if (p->v != fa && !vis[p->v]) getans(p->v, x, cur);
}
inline bool pointdiv(int x, int fa){
    int rt = getrt(x); vis[rt] = 1; h.clear();
    if (sz[x] < strlen(st)) return false;
    for (Node *p = g[rt]; p; p = p->nxt) if (!vis[p->v]){
        v.clear(); v.PB(w[rt]); getans(p->v, -1, w[rt]);
        for (VIT i = v.begin(); i != v.end(); i++){
            if (goal1.find(*i) != goal1.end() && h.find(goal1[*i]) != h.end()) return true;
            if (goal2.find(*i) != goal2.end() && h.find(goal2[*i]) != h.end()) return true;
        }
        for (VIT i = v.begin(); i != v.end(); i++) h[*i] = 1;
    }
    for (Node *p = g[rt]; p; p = p->nxt)
        if (!vis[p->v]) if (pointdiv(p->v, rt)) return true;
    return false;
}
int main(){
    setIO();
    int case_T; scanf("%d", &case_T);
    REP(T, 1, case_T){
        scanf("%d", &n);
        REP(i, 1, n) g[i] = NULL; MS(vis);
        REP(i, 1, n - 1){
            int x, y; scanf("%d%d", &x, &y); addedge(x, y);
           }
        scanf("%s", w + 1); scanf("%s", st); calgoal(st);
        printf("Case #%d: ", T); puts(pointdiv(1, 0) ? "Find" : "Impossible");
    }
    return 0;
}

route

给一个 n ∗ m 的矩阵,矩阵的每个格子上有一个不超过 30 的非负整数。
我们定义一条合法的路线是从(1,1)开始只能向右和向下移动到达(n,m)的路线。
定义数列 A1,A2,A3,..,An+m1 为一条合法路线上的序列,且 Aavg 为该数列的平均值。该路线的价值为 (n+m−1)乘上该数列的方差。即价值的表达式为 (n+m1)n+m1i=1(AiAavg)2
请找一条价值最小的路线,并输出这个价值。
Input
第一行两个正整数 n, m,表示矩阵的行数和列数。
以下 n 行每行 m 个非负整数 a i,j 表示矩阵上的数。
Output
包含一个整数,最小化的路线的价值。
Scoring
• 对于 30% 的数据,n, m, a i,j ≤ 10。
• 对于 60% 的数据,n, m, a i,j ≤ 15。
• 对于 100% 的数据,n, m, a i,j ≤ 30。

Solution :
化简一下式子发现就是 (n+m1)A2iS2S
于是dp

Code :

#include <bits/stdc++.h>
using namespace std;

const int N = 33;
const int M = 33;
const int S = (N + M) * N;
const int INF = 0x3f3f3f3f;
int n, m, a[N][M], f[N][M][S];

int main(){
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d", &a[i][j]);

    memset(f, 0x3f, sizeof(f));
    f[0][1][0] = f[1][0][0] = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                for (int k = 0; k <= S; k++)
                    if (k >= a[i][j])
        f[i][j][k] = min(f[i - 1][j][k - a[i][j]] + a[i][j] * a[i][j],
                              f[i][j - 1][k - a[i][j]] + a[i][j] * a[i][j]);

    long long ans = INF;
        for (int k = 0; k <= S; k++)
        ans = min(ans, 1ll * (n + m - 1) * f[n][m][k] - 1ll * k * k);
    printf("%I64d\n", ans);
        return 0;
}

你可能感兴趣的:([20151017]SCZ训练)