B. 字符路径

给一个含n个点m条边的有向无环图(允许重边,点用1到n的整数表示),每条边上有一个字符,问图上有几条路径满足路径上经过的边上的字符组成的的字符串去掉空格后以大写字母开头,句号 '.' 结尾,中间都是小写字母,小写字母可以为0个。

dp[x][0]为全空格的方案, dp[x][1]为空格加字母的方案, dp[x][2]为合法路径数.

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <math.h>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <string.h>
#include <bitset>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, P2 = 998244353, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head const int N = 1e6+10;
int n, m, deg[N], dp[N][3];
struct _ {int to;char w;};
vector<_> g[N];
queue<int> q; int main() {
scanf("%d%d", &n, &m);
REP(i,1,m) {
int u, v;
char w;
scanf("%d%d %c", &u, &v, &w);
g[u].pb({v,w});
++deg[v];
}
REP(i,1,n) if (!deg[i]) q.push(i);
unsigned ans = 0;
while (q.size()) {
int u = q.front(); q.pop();
ans += dp[u][2];
for (_ e:g[u]) {
int v = e.to;
if (isupper(e.w)) {
dp[v][1] += dp[u][0]+1;
}
else if (islower(e.w)) {
dp[v][1] += dp[u][1];
}
else if (e.w=='_') {
dp[v][0] += dp[u][0]+1;
dp[v][1] += dp[u][1];
dp[v][2] += dp[u][2];
}
else if (e.w=='.') {
dp[v][2] += dp[u][1];
}
if (!--deg[v]) q.push(v);
}
}
printf("%u\n", ans);
}

D.整数序列

大意: 区间加, 求区间sin和.

线段树维护, 注意爆int

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <math.h>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <string.h>
#include <bitset>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int n, m, a[N];
struct _ {
double c, s;
ll tag;
void upd(int x) {
tie(c,s) = pair<double,double>(c*cos(x)-s*sin(x),c*sin(x)+s*cos(x));
tag += x;
}
_ operator + (const _ & rhs) const {
return {c+rhs.c,s+rhs.s,0ll};
}
} tr[N<<2]; void pd(int o) {
if (tr[o].tag) {
tr[lc].upd(tr[o].tag),tr[rc].upd(tr[o].tag);
tr[o].tag = 0;
}
}
void build(int o, int l, int r) {
if (l==r) tr[o]={cos(a[l]),sin(a[l]),0ll};
else build(ls),build(rs),tr[o]=tr[lc]+tr[rc];
}
void update(int o, int l, int r, int ql, int qr, int v) {
if (ql<=l&&r<=qr) return tr[o].upd(v);
pd(o);
if (mid>=ql) update(ls,ql,qr,v);
if (mid<qr) update(rs,ql,qr,v);
tr[o]=tr[lc]+tr[rc];
}
double query(int o, int l, int r, int ql, int qr) {
if (ql<=l&&r<=qr) return tr[o].s;
pd(o);
double ans = 0;
if (mid>=ql) ans += query(ls,ql,qr);
if (mid<qr) ans += query(rs,ql,qr);
return ans;
} int main() {
scanf("%d", &n);
REP(i,1,n) scanf("%d", a+i);
build(1,1,n);
scanf("%d", &m);
while (m--) {
int op,l,r,v;
scanf("%d%d%d",&op,&l,&r);
if (op==1) {
scanf("%d", &v);
update(1,1,n,l,r,v);
}
else if (op==2) printf("%.1lf\n", query(1,1,n,l,r));
}
}

E. 骨牌覆盖

给定棋盘, 一些格子有挡板, 求骨牌摆放方案数.

04-28 22:32