T1 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
利用简单数学思想,先将区间长度中每个位置往前往后分别有多少B算出来,然后通过一系列处理算出 l 在区间的哪个位置,r 在区间的哪个位置,l r 中共有多少个区间(直接%)即可。
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
int preb[105],nexb[105];
char s[105];
int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
long long n;
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++)
{
if(s[i]=='R')
preb[i]=preb[i-1];
else
preb[i]=preb[i-1]+1;
}
for(int i=n;i>=1;i--)
{
if(s[i]=='R')
nexb[i]=nexb[i+1];
else
nexb[i]=nexb[i+1]+1;
}
long long l,r;
scanf(AUTO,&l);scanf(AUTO,&r);
long long left=l%n;
if(left==0)left=n;
long long tmp=n-left;
long long mid=r-(tmp+l);
long long num=mid/n;
mid%=n;
long long ans=nexb[left]+num*preb[n]+preb[mid];
printf(AUTO,ans);
return 0;
}
T2 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,开一个1<<18的数组,枚举状态推。
for(int k=0;k<n;k++)//枚举哪一个没吃
if(((i>>k)&1)==0)//如果这一位为0表示没吃
for(int j=0;j<n;j++)//枚举哪一个是最后吃的
if((1<<j)&i)//如果这一位为1表示吃了
dp[i|(1<<k)][k]=max(dp[i][j]+mp[j][k]+a[k],dp[i|(1<<k)][k]);
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
long long add[20][20],f[19][262145],d[20];
int cnt[19][48625];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline long long maxn(long long a,long long b)
{
if(a>b)return a;
return b;
}
int main()
{
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
int n=read(),m=read(),K=read();
for(int i=1;i<=n;++i)
scanf(AUTO,&d[i]);
for(int i=1;i<=K;++i)
{
int a=read(),b=read();
scanf(AUTO,&add[a][b]);
}
for(int i=0;i<=(1<<n)-1;++i)
{
int p=i,num=0;
while(p)
{
if((p&1)==1)
num++;
p=p>>1;
}
cnt[num][++cnt[num][0]]=i;
}
for(int i=1;i<=n;i++)
f[i][1<<(i-1)]=d[i];
for(int k=0;k<=(1<<n)-1;++k)
for(int i=0;i<=n-1;++i)
if(((k>>i)&1)==1)
for(int j=0;j<=n-1;++j)
if(((k>>j)&1)==0)
f[j+1][k|(1<<j)]=max(f[j+1][k|(1<<j)],f[i+1][k]+add[i+1][j+1]+d[j+1]);
long long ans=0;
for(int i=1;i<=n;++i)
for(int k=1;k<=cnt[m][0];++k)
ans=maxn(ans,f[i][cnt[m][k]]);
printf(AUTO,ans);
return 0;
}
T3 C
题目描述
历史上有一个著名的王国。它的所有城市互相连通并且构成一棵树。城市1为首都也就是这棵树的根。
因为外来的入侵,国王决定在某些城市加派士兵。所有城市初始士兵数量为0。当城市 i 被加派了 k 名士兵时,城市 i 的所有子城市需要被加派 k+1 名士兵,这些子城市的所有子城市需要被加派 k+2 名士兵,以此类推。
当然,加派士兵的同时,国王也需要不断了解当前的情况。于是他随时可能询问以城市 i 为根的子树中的所有城市共被加派了多少士兵。
你现在是国王的军事大臣,你能回答出国王的每个询问么?
输入
第一行,包含两个整数N,P代表城市数量以及国王的命令的数量。
接下来的1行为N-1个数,第 i 个数表示第 i+1 号城市的父亲城市。
接下来的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
因为第二题花了太多时间,导致第三题暴力都没码好…时间分配出了问题。第三题写出来了,但还是有点不懂,边写博客边理一理思路吧。
正解:对树做一次dfs生成一个2*N的序列,L[u],R[u]分别表示刚进入子树u时的dfs序列位置和刚处理完子树u时的dfs序列位置。则l[u]到r[u]这一段便是子树u的所有节点,然后我们就可以以线段树的方法来更新。
设 u 为一个父节点,v 为该节点子树中的一个节点,如果此时 u 加了 k 那么不难发现 v 就要加 deep[v]-deep[u]+k,而对于v来说 deep[v] 是不变的,那么我们可以定义一个数组记录每次的 k-deep[u]。另外,由于每次还要加上 deep[v] 那么定义另一个数组记录 deep[v] 访问了多少次。记 dep 表示给节点及其子树的所有深度之和,tot 表示访问了多少次,delta 表示 k-deep[u] 那一坨,size 表示该节点有多少棵子树,sum1 表示:深度之和×访问次数,sum2 表示 k-deep[u] 那一坨×子树数量。由之前推出的公式,节点 u 的答案等于 Σdeep×tot+delta×size=sum1+sum2。
表示静态查错查了很久,线段树什么的最烦了。
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Lson(u) u<<1
#define Rson(u) (u<<1)|1
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
struct node{
long long sum1,sum2,tot,delta,dep,size;
}gg[200020];
int head[50005],tov[50005],nex[50005],cnt;
int deep[50005],L[50005],R[50005],n,step,q,rank[50005];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void add(int a,int b)
{
tov[++cnt]=b;
nex[cnt]=head[a];
head[a]=cnt;
}
void dfs(int k,int dep)
{
L[k]=++step;rank[step]=k;deep[k]=dep;
int t=head[k];
while(tov[t])
{
dfs(tov[t],dep+1);t=nex[t];
}
R[k]=step;
}
void pushup(int k)
{
gg[k].dep=gg[Lson(k)].dep+gg[Rson(k)].dep;
gg[k].size=gg[Lson(k)].size+gg[Rson(k)].size;
}
void build(int l,int r,int k)
{
if(l==r)
{
gg[k].dep=deep[rank[l]];gg[k].size=1;return ;
}
int mid=(l+r)>>1;
build(l,mid,Lson(k));build(mid+1,r,Rson(k));
pushup(k);
}
void add1(int k,int val)
{
gg[k].tot+=val;gg[k].sum1+=gg[k].dep*val;
}
void pushdown1(int k)
{
if(!gg[k].tot)return ;
add1(Lson(k),gg[k].tot);add1(Rson(k),gg[k].tot);
gg[k].tot=0;
}
void pushup1(int k)
{
gg[k].sum1=gg[Lson(k)].sum1+gg[Rson(k)].sum1;
}
void update1(int l,int r,int k,int gl,int gr,int add)
{
if(l==gl&&r==gr)
{
add1(k,add);return ;
}
pushdown1(k);
int mid=(l+r)>>1;
if(mid>=gr)update1(l,mid,Lson(k),gl,gr,add);
else if(mid<gl)update1(mid+1,r,Rson(k),gl,gr,add);
else
{
update1(l,mid,Lson(k),gl,mid,add);update1(mid+1,r,Rson(k),mid+1,gr,add);
}
pushup1(k);
}
void add2(int k,int val)
{
gg[k].delta+=val;gg[k].sum2+=val*gg[k].size;
}
void pushdown2(int k)
{
if(!gg[k].delta)return ;
add2(Lson(k),gg[k].delta);add2(Rson(k),gg[k].delta);
gg[k].delta=0;
}
void pushup2(int k)
{
gg[k].sum2=gg[Lson(k)].sum2+gg[Rson(k)].sum2;
}
void update2(int l,int r,int k,int gl,int gr,int add)
{
if(l==gl&&r==gr)
{
add2(k,add);return ;
}
pushdown2(k);
int mid=(l+r)>>1;
if(mid>=gr)update2(l,mid,Lson(k),gl,gr,add);
else if(mid<gl)update2(mid+1,r,Rson(k),gl,gr,add);
else
{
update2(l,mid,Lson(k),gl,mid,add);update2(mid+1,r,Rson(k),mid+1,gr,add);
}
pushup2(k);
}
long long query(int l,int r,int k,int gl,int gr)
{
if(l==gl&&r==gr)
return gg[k].sum1+gg[k].sum2;
pushdown1(k);pushdown2(k);
int mid=(l+r)>>1;
if(mid>=gr)return query(l,mid,Lson(k),gl,gr);
else if(mid<gl)return query(mid+1,r,Rson(k),gl,gr);
else
return query(l,mid,Lson(k),gl,mid)+query(mid+1,r,Rson(k),mid+1,gr);
}
int main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
n=read();q=read();deep[1]=1;
for(int i=2;i<=n;i++)
{
int a=read();
add(a,i);
}
dfs(1,1);build(1,n,1);
while(q--)
{
char c=getchar();
while(c!='Q'&&c!='A')
c=getchar();
if(c=='Q')
{
int a=read();printf(AUTO,query(1,n,1,L[a],R[a]));printf("\n");
}
else
{
int a=read(),b=read();
update1(1,n,1,L[a],R[a],1);
update2(1,n,1,L[a],R[a],b-deep[a]);
}
}
return 0;
}