Codeforces Round #447 (Div. 2)

我感觉这场CF还是比较毒的,虽然我上分了。。。

Problem A  QAQ

题目大意:给你一个由小写字母构成的字符串,问你里面有多少个QAQ。

思路:找字符串中的A然后找两边的Q即可,可以枚举找Q,也可以前缀和优化一下。

 #include<bits/stdc++.h>
using namespace std;
char s[];
int sum[];
long long ans;
int main()
{
scanf("%s",s+);
int n=strlen(s+);
for(int i=;i<=n;i++)
{
sum[i]=sum[i-];
if(s[i]=='Q') sum[i]++;
}
int all=sum[n];
for(int i=;i<=n;i++)
{
if(s[i]!='A') continue;
ans+=(long long)(sum[i])*(all-sum[i]);
}
cout<<ans<<endl;
return ;
}

Problem B Ralph And His Magic Field

题目大意:给你n(n<=1e18),m (m<=1e18),k(k==1 || k==-1),说明是一个n行m列的一个矩阵,现在让你往这个矩阵里面填数字,

使得每一行每一列的数字的乘积微为k。

思路:刚开始看到的时候在想公式,然后想不出来,后来打了个表找出了规律,答案是(2^(n-1))^(m-1),然后套一下快速幂就好啦。

 #include<bits/stdc++.h>
#define ll long long
using namespace std;
long long n,m,k;
long long mod=1e9+;
long long modexp(long long a, long long b, int mod)
{
long long res=;
while(b>)
{
a=a%mod;
if(b&) res=res*a%mod;
b=b>>;
a=a*a%mod;
}
return res;
}
int main()
{
cin>>n>>m>>k;
if(k==- && (n+m)&)
{
puts("");
return ;
}
ll ans=;
ll g=modexp(,n-,mod);
ans=modexp(g,m-,mod);
cout<<ans<<endl;
return ;
}

Problem C Marco and GCD Sequence

题目大意:给你一个从小到大集合,这个集合的元素是另外一个数列连续子段的gcd的集合,让你构造出这个数列。

思路:比赛的时候想的是判断一下原序列任意两个的gcd是不是在这个序列里边,如果全部都在输出原序列,否则

输出-1,结果终判被卡掉了。。。

正确解法是看原序列里每一个元素是否能被第一个元素整除,如果都能整除就在每个元素后边插入第一个元素,然

后输出就可以啦,因为第一个元素肯定是原数列所有所有数字的gcd,那么我们在集合每个元素后边插入第一个元素

构成的数列的连续子段的gcd要么是本身要么是集合的第一个元素。

#include<bits/stdc++.h>
using namespace std;
const int N=;
int m,a[N];
int main()
{
scanf("%d",&m);
for(int i=;i<=m;i++) scanf("%d",&a[i]);
for(int i=;i<=m;i++)
{
if(a[i]%a[])
{
puts("-1");
return ;
}
}
printf("%d\n",*m);
for(int i=;i<=m;i++)
{
printf("%d ",a[i]);
printf("%d ",a[]);
}
puts("");
return ;
}

Problem D Ralph And His Tour in Binary Country

题目大意:给你一棵按顺序构建的二叉树,给你这些边的权值,由m个询问,每个询问给你一个A和一个H,A是出发点

H是愉悦值,每个点的权值为这个点到A的距离d,然后求所有d-H>=0 的点的(d-H)的和。

思路:每个二叉树的节点保存左子树所有点到当前点的距离,右子树所有点到当前点的距离,然后对这两个序列排序,

并且求前缀和。 然后对于每次询问我们要的答案就是,通过二分A节点保存的序列 对下边的子树求贡献,加到答案里,

然后不断地找A的祖先,将之前没有计算过的贡献加到答案里面,查询复杂度为O(m logn logn)。

 #include<bits/stdc++.h>
#define pii pair<int,int>
#define mk make_pair
using namespace std;
const int N=1e6+,M=1e5+;
int n,m;
vector<long long> vec[][N];
vector<long long> e[N];
void build(int cur)
{
if((cur<<)<=n)
{
build(cur<<);
long long g=e[cur][];
for(int i:vec[][cur<<]) vec[][cur].push_back(g+i);
for(int i:vec[][cur<<]) vec[][cur].push_back(g+i);
vec[][cur].push_back(g);
sort(vec[][cur].begin(),vec[][cur].end());
}
if((cur<<|)<=n)
{
build(cur<<|);
long long g=e[cur][];
for(int i:vec[][cur<<|]) vec[][cur].push_back(g+i);
for(int i:vec[][cur<<|]) vec[][cur].push_back(g+i);
vec[][cur].push_back(g);
sort(vec[][cur].begin(),vec[][cur].end());
}
vec[][cur].resize(vec[][cur].size());
vec[][cur].resize(vec[][cur].size());
for(int i=;i<vec[][cur].size();i++)
{
vec[][cur][i]=vec[][cur][i];
if(i) vec[][cur][i]+=vec[][cur][i-];
}
for(int i=;i<vec[][cur].size();i++)
{
vec[][cur][i]=vec[][cur][i];
if(i) vec[][cur][i]+=vec[][cur][i-];
}
}
long long work(int v,int H)
{
long long ans=;
int flag=-,item=-;
long long pre=;
while(v)
{
if(pre<=H) ans=ans+H-pre;
else break;
if(flag!= && vec[][v].size())
{
item=lower_bound(vec[][v].begin(),vec[][v].end(),H-pre)-vec[][v].begin();
if(item) ans=ans-vec[][v][item-]+(long long)(item)*(H-pre); }
if(flag!= && vec[][v].size())
{
item=lower_bound(vec[][v].begin(),vec[][v].end(),H-pre)-vec[][v].begin();
if(item) ans=ans-vec[][v][item-]+(long long)(item)*(H-pre);
}
int nx=v>>,g;
if(nx==) break;
if(v&) flag=,g=e[nx][];
else flag=,g=e[nx][];
pre+=g; v=nx;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int L; scanf("%d",&L);
e[(i+)/].push_back(L);
}
build();
while(m--)
{
int A,H; scanf("%d%d",&A,&H);
long long ans=work(A,H);
printf("%I64d\n",ans);
}
return ;
}

Problem E Ralph and Mushrooms

题目大意:给你n个点,m条边,每条边有个权值k,还有一个人在起点s。每条边经过1次后权值减1,经过第二次权值减2

……,然后问你这个人走过路的权值和最大为多少。

思路:先求强联通分量,然后缩点,可以知道一个强连通分量里任意两个点之间的边最后肯定为0。所以我们可以扫一遍所

有边,如果这条边两端的点属于同一个强连通分量则将这条边对应的贡献加到这个强连通分量上,否则我们将对应的两个

强连通分量连接起来。 最后dfs在拓扑图上进行记忆话搜索就能得到答案。

 #include<bits/stdc++.h>
#define ll long long
using namespace std;
const int P=1e6;
const int N=2e6+;
const int M=2e6+;
const int inf=0x3f3f3f3f;
struct edge
{
int f,t,next;
ll v;
}e[M];
int n,m,tot,all,s,cnt,head[N],dfn[N],low[N],st[N],id[N];
int dindex;
bool inst[N];
ll num[N],sum[],val[N];
void add(int f,int t,ll v)
{
e[tot].f=f; e[tot].t=t; e[tot].v=v;
e[tot].next=head[f]; head[f]=tot++;
}
void tarjan(int v)
{
dindex++;
dfn[v]=low[v]=dindex;
st[all++]=v; inst[v]=true;
for(int i=head[v];~i;i=e[i].next)
{
int nx=e[i].t;
if(!dfn[nx])
{
tarjan(nx);
low[v]=min(low[v],low[nx]);
}
else if(inst[nx]) low[v]=min(low[v],dfn[nx]);
}
if(dfn[v]==low[v])
{
cnt++;
while()
{
int cur=st[--all];
inst[cur]=false;
id[cur]=cnt;
if(cur==v) break;
}
}
}
ll work(ll x)
{
ll ans=;
int item=lower_bound(num,num+,x)-num;
ans-=sum[item];
ans+=x*(item+);
ans+=num[item]-x;
return ans;
}
ll dfs(int v)
{
ll res=;
dfn[v]=;
for(int i=head[v];~i;i=e[i].next)
{
int nx=e[i].t;
if(!dfn[nx]) res=max(res,e[i].v+dfs(nx));
else res=max(res,val[nx]+e[i].v);
}
val[v]+=res;
return val[v];
}
int main()
{
num[]=; cnt=; all=; tot=; dindex=;
for(int i=;i<=;i++) num[i]=num[i-]+i,sum[i]=sum[i-]+num[i];
memset(head,-,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int f,t; ll v;
scanf("%d%d%lld",&f,&t,&v);
add(f,t,v);
}
scanf("%d",&s);
tarjan(s);
int up=tot;
for(int i=;i<up;i++)
{
int a=e[i].f,b=e[i].t;
if(!id[a] || !id[b]) continue;
if(id[a]==id[b]) val[id[a]+P]+=work(e[i].v);
else if(id[a]<id[b]) add(id[b]+P,id[a]+P,e[i].v);
else add(id[a]+P,id[b]+P,e[i].v);
}
ll ans=dfs(id[s]+P);
printf("%lld\n",ans);
return ;
}
上一篇:JAVA定时任务实现的几种方式


下一篇:一个链接引发的血案---------服务器 IO及网络流量暴涨解决历程