暴力枚举第一个数字和第二个数字(99*99),判断是否满足GPB的条件即可。
判断是否满足条件的话就乱搞一下就可以了,具体看代码。
#include
#include
#include
#include
using namespace std;
typedef pair<int, int> PII;
char a[10], b[10];
bool B[10];
int P[10];
int G[10];
bool vis[10];
int cnt[10];
bool check(int i, int j, int k)
{
vector<int> c(10);
c[0] = i / 10, c[1] = i % 10;
c[3] = j / 10, c[4] = j % 10;
c[6] = k / 10, c[7] = k % 10;
for (int i = 0; i < 10; i ++ )
cnt[i] = 0;
for (int j = 0; j <= 7; j ++ )
if (j != 2 && j != 5)
cnt[c[j]] ++;
for (int j = 0; j <= 7; j ++ )
{
if (j == 2 || j == 5) continue;
if (b[j] == 'G')
{
if (c[j] != a[j] - '0') return false;
}
else
{
if (c[j] == a[j] - '0') return false;
if (b[j] == 'B')
{
if (cnt[a[j] - '0'] != G[a[j] - '0'] + P[a[j] - '0'])
return false;
}
}
}
for (int i = 0; i < 10; i ++ )
if (cnt[i] - G[i] < P[i]) return false;
return true;
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
scanf("%s", a);
scanf("%s", b);
for (int i = 0; b[i]; i ++ )
if (b[i] == 'B')
B[a[i] - '0'] = true;
else if(b[i] == 'P')
P[a[i] - '0'] ++;
else if (b[i] == 'G' && a[i] != '+' && a[i] != '=')
G[a[i] - '0'] ++;
vector<PII> ans;
for (int i = 0; i <= 99; i ++ )
for (int j = 0; j <= 99; j ++ )
if (i + j <= 99 && check(i, j, i + j))
ans.push_back(make_pair(i, j));
int sz = ans.size();
printf("%d\n", sz);
for (int i = 0; i < sz; i ++ )
printf("%d%d+%d%d=%d%d\n", ans[i].first / 10, ans[i].first % 10, ans[i].second / 10, ans[i].second % 10, (ans[i].first + ans[i].second) / 10, (ans[i].first + ans[i].second) % 10);
return 0;
}
令 f [ i ] [ j ] f[i][j] f[i][j]表示包含 F [ 1.. i ] F[1..i] F[1..i]的以 S [ j ] S[j] S[j]结尾的子串中,最短的子串的开始位置,那么显然有以下转移方程:
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] ) , ( S [ k ] = = F [ i − 1 ] , k < = j − 1 ) f[i][j] = max(f[i - 1][k]), (S[k] == F[i - 1], k <= j - 1) f[i][j]=max(f[i−1][k]),(S[k]==F[i−1],k<=j−1)
由于要满足 S [ k ] = = F [ i − 1 ] S[k] == F[i - 1] S[k]==F[i−1],于是只需要记下每个字符的 f [ i − 1 ] f[i - 1] f[i−1]的最大前缀状态(这个前缀是针对于S串中的位置)即可实现 O ( 1 ) O(1) O(1)转移,详细见代码。
#include
#include
#include
using namespace std;
const int N = 100005, INF = 0x3f3f3f3f;
int n, m;
char S[N], F[105];
int f[105][N];
int mx[N][36];
int get(char c)
{
if (c >= '0' && c <= '9') return c - '0';
else return c - 'a' + 10;
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
int _; scanf("%d", &_);
while (_ --)
{
scanf("%s", S + 1);
scanf("%s", F + 1);
n = strlen(S + 1);
m = strlen(F + 1);
for (int j = 1; j <= n; j ++ )
{
for (int i = 0; i < 36; i ++ )
mx[j][i] = mx[j - 1][i];
mx[j][get(S[j])] = j;
}
for (int i = 1; i <= m; i ++ )
for (int j = 1; j <= n; j ++ )
f[i][j] = -1;
for (int i = 1; i <= n; i ++ )
if (S[i] == F[1])
f[1][i] = i;
for (int i = 2; i <= m; i ++ )
for (int j = 1; j <= n; j ++ )
if (S[j] == F[i] && mx[j - 1][get(F[i - 1])])
f[i][j] = f[i - 1][mx[j - 1][get(F[i - 1])]];
int pos = 0, ans = n + 1;
for (int i = 1; i <= n; i ++ )
if (S[i] == F[m] && f[m][i] != -1)
{
int len = i - f[m][i] + 1;
if (len < ans)
ans = len, pos = i;
}
// printf("pos = %d ans = %d\n", pos, ans);
for (int i = pos - ans + 1; i <= pos; i ++ )
printf("%c", S[i]);
puts("");
}
return 0;
}
实际造成伤害的次数为时间内休息时间段的段数加一,即为 S ∗ R / 60 + 1 S * R / 60 + 1 S∗R/60+1,那么算出理论最高伤害与实际伤害 D D D比较即可,注意特判 R = 0 R=0 R=0的情况。
#include
using namespace std;
typedef long long LL;
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
int _; scanf("%d", &_);
while (_ --)
{
int B, R, D, S;
scanf("%d%d%d%d", &B, &R, &D, &S);
if (R == 0)
{
if (D)
puts("gua!");
else puts("ok");
continue;
}
LL t = S * R / 60 + 1;
t *= B;
if (D <= t)
puts("ok");
else puts("gua!");
}
return 0;
}
vp时队友写滴,就是判断有没有一段连续段(考虑了环之后的)长度大于 k k k,没有的话则无解。有解的情况下,最优解就是每一段暴力涂满,最优次数也就是段的长度除以k上取整。
#include
#include
#include
#include
using namespace std;
int t,m,n,k,col[1000005],fir,las,ans,colm[1000005],u;
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&k);
u=0;
col[0]=0;
ans=0;
for(int i=1;i<=m;i++)
{
scanf("%d",&col[i]);
if(col[i]!=col[i-1])
{
u++;
colm[u]=1;
}
else
{
colm[u]++;
}
}
if(col[1]==col[m]&&u!=1)
{
colm[1]+=colm[u];
colm[u]=0;
u--;
}
int flag=0;
for(int i=1;i<=u;i++)
{
if(colm[i]>=k)
{
flag=1;
}
ans+=(colm[i]+k-1)/k;
}
if(flag)printf("%d\n",ans);
else printf("-1\n");
}
}
我们把每个人抽象为一个点,把每次比赛抽象成连边,那么题目的限制就是,不能重边不能自环,每个点的度数不能超过2。故最终形成的图里,只有孤立点、链和环三种可能。
于是原题意转化为,每一次随机找两个点连边,如果连边之后的图不满足限制,则该边不加进图中,如果当前图中不存在点对使得连边之后仍然满足限制,则停止连边,问停止的期望次数。
由于图中只有孤立点、链和环三种可能,考虑一下所有合法的连边:
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 205;
int n;
double f[N][N][N];
double dfs(int i, int j, int k)
{
if (f[i][j][k] != -1) return f[i][j][k];
f[i][j][k] = 0;
int all = 0;
if (i >= 2) all += i * (i - 1), f[i][j][k] += (dfs(i - 2, j + 1, k) + 1) * i * (i - 1);
if (i >= 1 && j >= 1) all += i * 4 * j, f[i][j][k] += (dfs(i - 1, j - 1, k + 1) + 1) * i * 4 * j;
if (i >= 1) all += i * 4 * k, f[i][j][k] += (dfs(i - 1, j, k) + 1) * i * 4 * k;
if (j >= 2) all += j * (j - 1) * 4, f[i][j][k] += (dfs(i, j - 2, k + 1) + 1) * j * (j - 1) * 4;
if (j >= 1) all += j * k * 8, f[i][j][k] += (dfs(i, j - 1, k) + 1) * j * k * 8;
if (k >= 1) all += k * (k - 1) * 4, f[i][j][k] += ( dfs(i, j, k - 1) + 1 ) * k * (k - 1) * 4;
if (k >= 1) all += 2 * k, f[i][j][k] += (dfs(i, j, k - 1) + 1) * 2 * k;
f[i][j][k] += n * n - all;
f[i][j][k] /= all;
return f[i][j][k];
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
scanf("%d", &n);
for (int i = 0; i <= n; i ++ )
for (int j = 0; j <= n; j ++ )
for (int k = 0; k <= n; k ++ )
f[i][j][k] = -1;
f[1][0][0] = f[0][1][0] = f[0][0][0] = 0;
printf("%.10f\n", dfs(n, 0, 0));
return 0;
}
不难想到一个状态定义,定义 f [ i ] f[i] f[i]表示 s [ 1... i ] s[1...i] s[1...i]中所有分配方案的分数和,令在 s [ i ] s[i] s[i]位置匹配上的 t t t串集合为 S S S,则有以下转移方程:
f [ i ] = ∑ j f [ i − l e n [ j ] + 1 ] + v a l [ j ] , t j ⊂ S f[i]=\sum_{j}f[i-len[j]+1]+val[j],t_j \subset S f[i]=∑jf[i−len[j]+1]+val[j],tj⊂S
可以考虑利用AC自动机找到以 s [ i ] s[i] s[i]结尾的所有匹配的串(集合 S S S),直接在AC自动机上跳fail即可找到所有串,但是可能会超时。
考虑优化跳fail的过程,我们可以dfs一遍保存每个AC自动机上的结点在fail树上最近的已标记祖先(已标记表示为某个t串的节点)
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 200005, mod = 998244353;
int n;
char s[N];
char t[N];
int ch[N][26];
int tot;
int fail[N], last[N];
int ed[N];
int f[N];
int len[N], val[N];
struct edge
{
int to, next;
}e[N << 1];
int head[N], cnt;
void add(int u, int v)
{
e[++ cnt] = {v, head[u]};
head[u] = cnt;
}
void insert(char s[], int idx)
{
int u = 0;
for (int i = 0; s[i]; i ++ )
{
int v = s[i] - 'a';
if (!ch[u][v]) ch[u][v] = ++ tot;
u = ch[u][v];
}
ed[u] = idx;
}
void get_fail()
{
queue<int> q;
for (int i = 0; i < 26; i ++ )
if (ch[0][i]) q.push(ch[0][i]), add(0, ch[0][i]);
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = 0; i < 26; i ++ )
{
if (ch[u][i])
{
fail[ch[u][i]] = ch[fail[u]][i];
add(fail[ch[u][i]], ch[u][i]);
q.push(ch[u][i]);
}
else ch[u][i] = ch[fail[u]][i];
}
}
}
void dfs(int u)
{
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (ed[u] == -1) last[v] = last[u];
else last[v] = u;
dfs(v);
}
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
memset(ed, -1, sizeof ed);
scanf("%s", s);
n = strlen(s);
int _;
scanf("%d", &_);
ed[0] = 0;
for (int i = 1; i <= _; i ++ )
{
scanf("%s", t), insert(t, i);
scanf("%d", &val[i]);
len[i] = strlen(t);
}
get_fail();
dfs(0);
// for (int i = 1; i <= n; i ++ )
// cout << "i = " << i << " fail[i] = " << fail[i] << endl;
// for (int i = 1; i <= n; i ++ )
// cout << "i = " << i << " last[i] = " << last[i] << endl;
// for (int i = 1; i <= n; i ++ )
// cout << "i = " << i << " ed[i] = " << ed[i] << endl;
f[0] = 1;
int u = 0;
for (int i = 0; s[i]; i ++ )
{
int v = s[i] - 'a';
u = ch[u][v];
int t = u;
if (ed[u] == -1) t = last[t];
while (t)
{
// cout << "u = " << u << endl;
f[i + 1] = (f[i + 1] + 1LL * f[i - len[ed[t]] + 1] * val[ed[t]] % mod) % mod;
t = last[t];
}
f[i + 1] = (f[i + 1] + f[i]) % mod;
}
for (int i = 1; i <= n; i ++ )
printf("%d ", f[i]);
puts("");
return 0;
}
由于一个学校强于另一个学校具有传递性,即若有学校A强于学校B,学校B强于学校C,则有学校A强于学校C,那么不难想到把弱的学校向强的学校连单向边,组成的图中,一个强连通分量内所有的学校都比连通块中的其他学校强,一个强连通分量中的所有学校都是等价的,那么缩点之后拓扑排序即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1000005;
int tot;
int a[N];
struct edge
{
int to, next;
}e[N << 1], e2[N << 1];
int head[N], cnt;
int head2[N], cnt2;
int dfn[N], low[N];
int stack[N], ins[N], c[N];
vector<int> scc[N];
int num, top, scc_cnt;
int in[N], etr[N];
int ans[N];
void add(int u, int v)
{
e[++ cnt] = {v, head[u]};
head[u] = cnt;
}
void add2(int u, int v)
{
e2[++ cnt2] = {v, head2[u]};
head2[u] = cnt2;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++ num;
stack[++ top] = u, ins[u] = 1;
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(ins[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u])
{
scc_cnt ++;int y;
do
{
y = stack[top --], ins[y] = 0;
c[y] = scc_cnt, scc[scc_cnt].push_back(y);
}while(u != y);
}
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
int n, m;
scanf("%d%d", &n, &m);
int t = 0;
for (int i = 1; i <= m; i ++ )
for (int j = 1; j <= n; j ++ )
{
scanf("%d", &a[++ t]);
if (j != 1)
add(a[t], a[t - 1]);
}
for (int i = 1; i <= n; i ++ )
if (!dfn[i])
tarjan(i);
// printf("%d\n", scc_cnt);
set<PII> s;
for (int u = 1; u <= n; u ++ )
{
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
PII t = make_pair(c[u], c[v]);
if (c[v] == c[u] || s.count(t)) continue;
s.insert(t);
add2(c[u], c[v]), in[c[v]] ++;
}
}
queue<int> q;
for (int i = 1; i <= scc_cnt; i ++ )
if (!in[i]) q.push(i);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head2[u]; i; i = e2[i].next)
{
int v = e2[i].to;
in[v] --;
etr[v] += scc[u].size() + etr[u];
if (!in[v])
q.push(v);
}
}
for (int i = 1; i <= scc_cnt; i ++ )
{
int sz = scc[i].size();
for (int j = 0; j < sz; j ++ )
{
int u = scc[i][j];
ans[u] = sz - 1 + etr[i];
}
}
for (int i = 1; i <= n; i ++ )
printf("%d ", ans[i]);
return 0;
}
判断两个字符串大小即可。代码略。