A
求一个字符串的回文子序列个数
很直观的DP但一开始看着这个题目愣了好久……
scanf("%s" , s + 1);
n = strlen(s + 1);
memset(f , 0 , sizeof(f));
for (i = 1 ; i <= n ; ++ i) f[i][i] = 1;
for (k = 2 ; k <= n ; ++ k)
{
for (i = 1 ; i + k - 1 <= n ; ++ i)
{
j = i + k - 1;
f[i][j] = f[i + 1][j] + f[i][j - 1];
if (s[i] == s[j])
f[i][j] ++;
else f[i][j] += (Q - f[i + 1][j - 1]);
f[i][j] %= Q;
}
}
printf("Case %d: %d\n" , ++ ca , f[1][n]);
C
先预处理出从某个点出发往四个方向滑的终点位置以及路过能拿到的钥匙
然后就是一个BFS了,边权只有1或0,开deque。
可惜因为没有发现卡墙的问题比赛时没有过这个题TwT
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
#define N 205
#define ULL unsigned long long
int n , m , sx , sy , ex , ey;
char s[N][N];
int dx[] = {1 , -1 , 0 , 0} , dy[] = {0 , 0 , 1 , -1};
pair<int , int> h[4][N][N] , null = make_pair(-1 , -1);
int kn[N][N], key[4][N][N] , ks , ans;
struct opt
{
int x , y , p , w , r;
};
deque<opt> q;
int d[N][N][128];
bool f[N][N][128];
void update(int x , int y , int p , int v , int w , int r)
{
if (!f[x][y][p])
{
if (w)
q.push_back((opt){x , y , p , v + w , r});
else q.push_front((opt){x , y , p , v + w , r});
}
}
void BFS()
{
int i , x , y , w , kk = (1 << ks) - 1;
ans = 1 << 30;
q.push_back((opt){sx , sy , 0 , 0 , 0});
memset(f , 0 , sizeof(f));
while (!q.empty())
{
opt a = q.front(); q.pop_front();
if (f[a.x][a.y][a.p]) continue;
f[a.x][a.y][a.p] = 1 , w = d[a.x][a.y][a.p] = a.w;
x = a.x , y = a.y;
cout << x <<' ' << y << ' ' << a.p << ' ' << w << endl;
if (x == ex && y == ey)
{
if (a.p == kk)
ans = min(ans , w);
i = a.r;
if (s[x + dx[i]][y + dy[i]] == '#' || h[i][x + dx[i]][y + dy[i]] == null) continue;
update(h[i][x + dx[i]][y + dy[i]].fi , h[i][x + dx[i]][y + dy[i]] .se , a.p | key[i][x + dx[i]][y + dy[i]] , w , 0 , i);
continue;
}
if (s[x][y] < 4)
{
i = s[x][y];
if (s[x + dx[i]][y + dy[i]] == '#' || h[i][x + dx[i]][y + dy[i]] == null) continue;
update(h[i][x + dx[i]][y + dy[i]].fi , h[i][x + dx[i]][y + dy[i]] .se , a.p | key[i][x + dx[i]][y + dy[i]] , w , 0 , i);
continue;
}
for (i = 0 ; i < 4 ; ++ i)
if (h[i][x][y] != null)
update(h[i][x][y].fi , h[i][x][y].se , a.p | key[i][x][y] , w , 1 , i);
}
if (ans == 1 << 30)
ans = -1;
printf("%d\n" , ans);
}
void work()
{
int i , j;
memset(s , 0 , sizeof(s));
memset(h , 0 , sizeof(h));
memset(kn , -1 , sizeof(kn));
memset(key , 0 , sizeof(key));
ks = 0;
for (i = 1 ; i <= n ; ++ i)
scanf("%s" , s[i] + 1);
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= m ; ++ j)
{
if (s[i][j] == 'S')
sx = i , sy = j;
if (s[i][j] == 'E')
ex = i , ey = j;
if (s[i][j] == 'K')
kn[i][j] = ks ++;
}
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= m ; ++ j)
{
if (s[i][j] == 'U')
s[i][j] = 1;
if (s[i][j] == 'D')
s[i][j] = 0;
if (s[i][j] == 'L')
s[i][j] = 3;
if (s[i][j] == 'R')
s[i][j] = 2;
}
for (i = n + 1; i > 0 ; -- i)
for (j = 1 ; j <= m ; ++ j)
{
if (i == n + 1) h[0][i][j] = null;
else
{
if (s[i][j] < 4 || s[i][j] == 'E') h[0][i][j] = make_pair(i , j) , key[0][i][j] = 0;
else if (s[i + 1][j] != '#')
{
h[0][i][j] = h[0][i + 1][j];
key[0][i][j] = key[0][i + 1][j];
key[0][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
else
{
h[0][i][j] = make_pair(i , j);
key[0][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
}
}
for (i = 0 ; i <= n ; ++ i)
for (j = 1 ; j <= m ; ++ j)
{
if (i == 0) h[1][i][j] = null;
else
{
if (s[i][j] < 4 || s[i][j] == 'E') h[1][i][j] = make_pair(i , j) , key[1][i][j] = 0;
else if (s[i - 1][j] != '#')
{
h[1][i][j] = h[1][i - 1][j];
key[1][i][j] = key[1][i - 1][j];
key[1][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
else
{
h[1][i][j] = make_pair(i , j);
key[1][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
}
}
for (j = m + 1 ; j > 0 ; -- j)
for (i = 1 ; i <= n ; ++ i)
{
if (j == m + 1) h[2][i][j] = null;
else
{
if (s[i][j] < 4 || s[i][j] == 'E') h[2][i][j] = make_pair(i , j) , key[2][i][j] = 0;
else if (s[i][j + 1] != '#')
{
h[2][i][j] = h[2][i][j + 1];
key[2][i][j] = key[2][i][j + 1];
key[2][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
else
{
h[2][i][j] = make_pair(i , j);
key[2][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
}
}
for (j = 0 ; j <= m ; ++ j)
for (i = 1 ; i <= n ; ++ i)
{
if (j == 0) h[3][i][j] = null;
else
{
if (s[i][j] < 4 || s[i][j] == 'E') h[3][i][j] = make_pair(i , j) , key[3][i][j] = 0;
else if (s[i][j - 1] != '#')
{
h[3][i][j] = h[3][i][j - 1];
key[3][i][j] = key[3][i][j - 1];
key[3][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
else
{
h[3][i][j] = make_pair(i , j);
key[3][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
}
}
}
BFS();
}
int main()
{
freopen("input.txt","r",stdin);
while (~scanf("%d%d",&n,&m))
work();
return 0;
}
D
SCC缩点之后再枚举割掉的所有入度为0或者出度为0的SCC,更新答案。
代码主要部分不是我写的
#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 100010
#define M 200010
int sum,first[N];
struct gtype {
int x,y,next;
}g[M];
int cas,n,m,a,b,tot,top,cnt,pin[N],pout[N];
int low[N],dfn[N],con[N],stack[N],belong[N];
bool instack[N];
bool cmp(int a, int b) {
return a>b;
}
void add(int x,int y) {
sum++;
g[sum].x = x;
g[sum].y = y;
g[sum].next = first[x];
first[x] = sum;
}
void tarjan(int x) {
int k;
dfn[x] = low[x] = ++tot;
instack[x] = true;
stack[++top] = x;
for (int t=first[x];t!=-1;t=g[t].next) {
int y = g[t].y;
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x],low[y]);
}
else if (instack[y]) low[x] = min(low[x],dfn[y]);
}
if (dfn[x]==low[x]) {
cnt++;
do {
k = stack[top--];
instack[k] = false;
belong[k] = cnt;
con[cnt]++;
}while (k!=x);
}
}
int main() {
scanf("%d",&cas);
for (int tt=1;tt<=cas;tt++) {
sum = 0;
memset(first,-1,sizeof(first));
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) {
scanf("%d%d",&a,&b);
add(a,b);
}
tot = top = cnt = 0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(con,0,sizeof(con));
memset(instack,0,sizeof(instack));
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i);
printf("Case %d: ",tt);
if (cnt==1) {
printf("-1\n");
}
else {
long long ans = 0;
memset(pin,0,sizeof(pin));
memset(pout,0,sizeof(pout));
for (int i=1;i<=m;i++) {
if (belong[g[i].x] != belong[g[i].y]) {
pout[belong[g[i].x]]++;
pin[belong[g[i].y]]++;
}
}
for (int i=1;i<=cnt;i++)
{
if (pin[i]==0)
{
ans = max(ans, (long long)n*(n-1)-m-(long long)(n-con[i])*con[i]);
}
if (pout[i]==0)
{
ans = max(ans, (long long)n*(n-1)-m-(long long)(n-con[i])*con[i]);
}
}
printf("%I64d\n",ans);
}
}
return 0;
}
G
比赛结束了才被DS提醒是被水了过去……
之前用线段树想的太麻烦,后来才发现可以用数组直接模拟分为了多少段
#pragma comment(linker,"/STACK:102400000,102400000")
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define maxn 100010
using namespace std;
typedef long long LL;
int pos[maxn],color[maxn],n,m;
void RD(int& x)
{
x = 0; char c;
for (c = getchar() ;!isdigit(c) ; c = getchar()); x = c - '0';
for (c = getchar() ; isdigit(c) ; c = getchar()) x = x * 10 + c - '0';
}
struct Question
{
int l,r,id;
int a;
friend bool operator < (const Question &a,const Question &b)
{
return pos[a.l]<pos[b.l]||(pos[a.l]==pos[b.l]&&a.r<b.r);
}
}ask[maxn];
bool cmp_id(const Question &a,const Question &b)
{
return a.id<b.id;
}
bool ff[maxn];
int anss;
void read()
{
RD(n) , RD(m);
memset(ff , 0 , sizeof(ff));
for(int i=1;i<=n;i++)
RD(color[i]);
int limit=(int)sqrt(n+0.5);
for(int j=1;j<=n;j++)
pos[j]=(j-1)/limit+1;
for(int i=1;i<=m;i++)
{
RD(ask[i].l) , RD(ask[i].r);
ask[i].id=i;
}
sort(ask+1,ask+m+1);
}
void Modify(int i,int add)
{
if (add == 1)
{
int x = color[i];
ff[x] = 1;
if (ff[x - 1] && ff[x + 1]) -- anss;
else if (!ff[x - 1] && !ff[x + 1]) ++ anss;
}
else
{
int x = color[i];
ff[x] = 0;
if (ff[x - 1] && ff[x + 1]) ++ anss;
else if (!ff[x - 1] && !ff[x + 1]) -- anss;
}
}
void work()
{
anss=0;
for(int i=1,l=1,r=0;i<=m;i++)
{
if(r<ask[i].r)
{
for(r=r+1;r<=ask[i].r;r++)
Modify(r,1);
r--;
}
if(r>ask[i].r)
for(;r>ask[i].r;r--)
Modify(r,-1);
if(l<ask[i].l)
for(;l<ask[i].l;l++)
Modify(l,-1);
else if(l>ask[i].l)
{
for(l=l-1;l>=ask[i].l;l--)
Modify(l,1);
l++;
}
ask[i].a=anss;
}
}
void print()
{
sort(ask+1,ask+m+1,cmp_id);
for(int i=1;i<=m;i++)
printf("%d\n",ask[i].a);
}
int main()
{
int _; RD(_); while (_--)
read(),
work(),
print();
return 0;
}
H
每一组hehehehe明显可以分开处理,一段长度为n的hehe....he的方案就是斐波那契的[n/2+1]项,乘起来就ok
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
#define N 15005
#define M 2000005
typedef long long LL;
using namespace std;
char s[N];
int n , m , a[N] , Q = 10007 , f[N] , ca;
void work()
{
int i , j , ans = 1 , x;
scanf("%s", s);
n = strlen(s);
m = 0;
for (i = 0 ; i + 3 < n ; ++ i)
if (s[i] == 'h' && s[i + 1] == 'e' && s[i + 2] == 'h' && s[i + 3] == 'e')
a[m ++] = i;
for (i = 0 ; i < m ; i = j)
{
j = i + 1 , x = 1;
while (a[j] - a[j - 1] == 2)
++ j , ++ x;
ans *= f[x] , ans %= Q;
}
printf("Case %d: %d\n" , ++ ca , ans);
}
int main()
{
f[0] = 1 , f[1] = 2;
for (int i = 2 ; i <= 10086 ; ++ i)
f[i] = f[i - 1] + f[i - 2] , f[i] %= Q;
int _; cin >> _ ; while (_ --)
work();
return 0;
}