给定一个单词,如果该单词以 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;
}
设有 1g, 2g, 3g, 5g, 10g, 20g 的砝码各若干枚(其总重 ≤ 100, 000),要求:计算用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况。
Input
一行,包括六个正整数a1,a2,a3,a4,a5,a6,表示1g砝码有a1个,2g砝码有a2个,......,20g砝码有a6个。相邻两个整数之间用单个空格隔开。
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;
}
给定一个 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 :
暂无
给定一棵 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;
}
给一个 n ∗ m 的矩阵,矩阵的每个格子上有一个不超过 30 的非负整数。
我们定义一条合法的路线是从(1,1)开始只能向右和向下移动到达(n,m)的路线。
定义数列
A1,A2,A3,..,An+m−1
为一条合法路线上的序列,且
Aavg
为该数列的平均值。该路线的价值为 (n+m−1)乘上该数列的方差。即价值的表达式为
(n+m−1)∑n+m−1i=1(Ai−Aavg)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+m−1)∑A2i−S2,S是和
于是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;
}