A
Statement
给出一个长度不超过100只包含’B’和’R’的字符串,将其无限重复下去。
比如,BBRB则会形成
BBRBBBRBBBRB
现在给出一个区间[l,r]询问该区间内有多少个字符’B’(区间下标从1开始)
Input
第一行为一个只包含’B’和’R’的字符串
第二行为两个整数,表示l和r
Output
输出[l,r]区间内字符’B’的数量
Sample Input
BBRB
4 8
Sample Output
4
Limit
1<=|S|<=100(字符串长度大于等于1,小于等于100)
1<=i<=r<=1e18
模拟,前缀和相减。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
x = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
x = (x<<1) + (x<<3) + ch - '0';
ch = (char)getchar();
}
x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int maxn = 105;
char s[maxn];
int sum[maxn];
LL L,R;
int n;
LL calc(LL x)
{
LL ret = sum[n] * (x/n);
ret += sum[x%n];
return ret;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%s"AUTO AUTO,s+1,&L,&R);
n = strlen(s+1);
for(int i=1;i<=n;i++) sum[i] = sum[i-1] + (s[i]=='B');
LL ans = calc(R) - calc(L-1);
printf(AUTO,ans);
return 0;
}
B
【题目描述】
我们要从n种食物选m个出来,安排一个顺序吃掉它(们),每种食物有个美味值ai,然后我们有k个规则,每个规则有 xi, yi 和 ci三个数,如果吃完第xi种食物接下来马上吃第yi种食物,第j种食物的美味值会增加ci。每种食物至多吃一个,求美味值最大的和是多少?
【输入格式】
第一行有三个数n,m,k,k代表有k个规则(0<=k<=n*(n-1))。
第二行有n个数字代表每个食物的美味值。
接下去有k行,每行三个数xi,yi,ci。保证没有任意两个规则的xi和yi同时相同。
【输出格式】
一行一个数代表答案
【sample input1】
2 2 1
1 1
2 1 1
【sample output1】
3
【sample input 2】
4 3 2
1 2 3 4
2 1 5
3 4 2
【sample output 2】
12
【数据范围】
30% m<=n<=5 ,0<=ci,ai<=1e5
100% m<=n<=18,0<=ci,ai<=1e9
数据范围剧透题解类型。。
状压DP
dp(S,i)表示已经选了的集合为S,最后一个选的是i的最大价值。
方程 :dp[S+{i}][i] = dp[S][j] + a[i] + g[j][i] , 其中 j 属于 S ,i 不属于S
每次如果S中1的个数为m,就更新答案。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
x = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
x = (x<<1) + (x<<3) + ch - '0';
ch = (char)getchar();
}
x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int maxS = (1<<18) + 5;
const int maxn = 20;
int a[maxn];
int g[maxn][maxn];
LL dp[maxS][maxn];
int n,m,k;
inline void init()
{
read(n); read(m); read(k);
for(int i=0;i<n;i++) read(a[i]);
for(int i=1;i<=k;i++)
{
int x,y,c;
read(x); read(y); read(c);
x--; y--;
g[x][y] += c;
}
}
LL dynamic()
{
LL ans = 0;
for(int i=0;i<n;i++) dp[(1<<i)][i] = a[i];
for(int S=1;S<(1<<n);S++)
if(__builtin_popcount(S) == m)
for(int i=0;i<n;i++)
if(S&(1<<i)) smax(ans,dp[S][i]);
else continue;
else
for(int i=0;i<n;i++) if(!(S&(1<<i))) // haven't been eaten
for(int j=0;j<n;j++) if(S&(1<<j)) // the last one
smax(dp[S|(1<<i)][i],dp[S][j]+a[i]+g[j][i]);
return ans;
}
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
init();
LL ans = dynamic();
printf(AUTO,ans);
return 0;
}
C
【题目描述】
历史上有一个著名的王国。它的所有城市互相连通并且构成一棵树。城市1
为首都也就是这棵树的根。
因为外来的入侵,国王决定在某些城市加派士兵。所有城市初始士兵数量
为0。当城市i 被加派了k 名士兵时。城市i 的所有子城市需要被加派k+1 名士
兵。这些子城市的所有子城市需要被加派k+2 名士兵。以此类推。
当然,加派士兵的同时,国王也需要不断了解当前的情况。于是他随时可
能询问以城市i 为根的子树中的所有城市共被加派了多少士兵。
你现在是国王的军事大臣,你能回答出国王的每个询问么?
【输入】
第一行,包含两个整数N,P 代表城市数量以及国王的命令的数量。
接下来的P 行,每行代表国王的一个命令,命令分两种
A X K 在城市X 加入K 个士兵
Q X 询问以城市X 为根的子树中所有士兵数量的和
【输出】
对于每个Q,输出答案。
【输入样例】
7 10
1 1 2 2 5 5
Q 1
A 2 1
Q 1
Q 2
Q 5
A 5 0
Q 5
A 3 1
Q 1
Q 2
【输出样例】
0
11
11
8
10
14
13
【数据范围】
对于50%的数据, 1<=N<=1000 1<=P<=300
对于100%的数据, 1<=N<=50000 1<=P<=100000 1<=X<=N 0<=K<=1000
50%:直接在节点做标记,每次查询时下传即可。考虑到树的形状不是平衡的,直接这样做肯定要T
100%:
每次操作都是对一个子树的操作,很容易想到在dfs序中区间修改和标记下传,这样就可以保证nlogn的时间复杂度了。
但是每个子树的修改时不一样的,新操作一次的贡献是k+depth[v]-depth[u],由于depth[v]是节点本身的性质,而k-depth[u]是这次操作的性质,那么可以考虑分成两部分来求解。
假设某个节点被操作了tot次(包括它的父亲的操作),那么这部分的贡献是tot*depth[v],对于一个子树来说,这部分总的贡献就是tot*Sigma(depth[v])。
再来处理操作的贡献。每一个节点都是k-depth[u],那么子树的贡献就是size*Sigma(k-depth[u])
这两部分分别用线段树来维护即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
x = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
x = (x<<1) + (x<<3) + ch - '0';
ch = (char)getchar();
}
x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
//end template
const int INF=0x3f3f3f3f;
const int maxn = 50005;
// original tree related
struct Edge
{
int to,next;
}edge[maxn<<1];
int head[maxn];
int maxedge;
inline void addedge(int u,int v)
{
edge[++maxedge] = (Edge) { v,head[u] };
head[u] = maxedge;
edge[++maxedge] = (Edge) { u,head[v] };
head[v] = maxedge;
}
int maxnode;
int id[maxn]; // from dfn to original node id
int pre[maxn],post[maxn]; // two dfs_clocks
int depth[maxn];
void dfs(int u,int father,int deep)
{
depth[u] = deep;
pre[u] = ++maxnode;
id[maxnode] = u;
for(int i=head[u];~i;i=edge[i].next)
{
int v = edge[i].to;
if(v == father) continue;
dfs(v,u,deep+1);
}
post[u] = maxnode;
}
// end original tree
// segment tree related
struct Node
{
LL dep,tot,sum_tot; // sum of depth[v] , total add (lazy) , sum part 1
LL delta,size,sum_delta; // sum of delta , total nodes (lazy) , sum part 2
}node[maxn<<2];
#define dep(x) node[x].dep
#define tot(x) node[x].tot
#define sum_tot(x) node[x].sum_tot
#define delta(x) node[x].delta
#define size(x) node[x].size
#define sum_delta(x) node[x].sum_delta
inline void add_tot(int root,LL val)
{
tot(root) += val;
sum_tot(root) += val * dep(root);
}
inline void add_delta(int root,LL val)
{
delta(root) += val;
sum_delta(root) += val * size(root);
}
inline void pushdown_tot(int root)
{
if(!tot(root)) return;
add_tot(root<<1,tot(root));
add_tot(root<<1|1,tot(root));
tot(root) = 0;
}
inline void pushdown_delta(int root)
{
if(!delta(root)) return;
add_delta(root<<1,delta(root));
add_delta(root<<1|1,delta(root));
delta(root) = 0;
}
inline void update_tot(int root) { sum_tot(root) = sum_tot(root<<1) + sum_tot(root<<1|1); }
inline void update_delta(int root) { sum_delta(root) = sum_delta(root<<1) + sum_delta(root<<1|1); }
void modify_tot(int root,int l,int r,int x,int y,LL val)
{
if(x<=l && r<=y)
{
add_tot(root,val);
return;
}
pushdown_tot(root);
int mid = (l+r)>>1;
if(x<=mid && l<=y) modify_tot(root<<1,l,mid,x,y,val);
if(y>=mid+1 && r>=x) modify_tot(root<<1|1,mid+1,r,x,y,val);
update_tot(root);
}
void modify_delta(int root,int l,int r,int x,int y,LL val)
{
if(x<=l && r<=y)
{
add_delta(root,val);
return;
}
pushdown_delta(root);
int mid = (l+r)>>1;
if(x<=mid && l<=y) modify_delta(root<<1,l,mid,x,y,val);
if(y>=mid+1 && r>=x) modify_delta(root<<1|1,mid+1,r,x,y,val);
update_delta(root);
}
LL query(int root,int l,int r,int x,int y)
{
if(x<=l && r<=y) return sum_tot(root)+sum_delta(root);
pushdown_tot(root); pushdown_delta(root);
int mid = (l+r)>>1;
LL ret = 0;
if(x<=mid && l<=y) ret += query(root<<1,l,mid,x,y);
if(y>=mid+1 && r>=x) ret += query(root<<1|1,mid+1,r,x,y);
return ret;
}
inline void update(int root)
{
dep(root) = dep(root<<1) + dep(root<<1|1);
size(root) = size(root<<1) + size(root<<1|1);
}
void build(int root,int l,int r)
{
if(l == r)
{
dep(root) = depth[id[l]];
size(root) = 1;
return;
}
int mid = (l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
update(root);
}
// end segment tree
// main
int n,q,Root;
inline void init()
{
memset(head,-1,sizeof(head)); maxedge=-1;
read(n); read(q); Root=1;
for(int i=2;i<=n;i++)
{
int to;
read(to);
addedge(i,to);
}
dfs(Root,-1,1);
build(1,1,n);
}
void work()
{
for(int i=1;i<=q;i++)
{
char ch = (char) getchar();
while(!isalpha(ch)) ch = (char) getchar();
int x,k;
read(x);
if(ch == 'Q')
{
LL ans = query(1,1,n,pre[x],post[x]);
printf(AUTO,ans);
putchar('\n');
}
else
{
read(k);
modify_tot(1,1,n,pre[x],post[x],1);
modify_delta(1,1,n,pre[x],post[x],k-depth[x]);
}
}
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
init();
work();
return 0;
}