题目链接:http://codeforces.com/contest/1076
A
题意:去掉一个字母,让串字典序最小。
思想:如果串是一个山峰形状,删掉第一个上峰坡,如果一直是降序就删掉第一个。
B
题意:给你一个n,可以执行减去一个最小的素数因子,问你最多执行多少步。
思想:模拟,本身是素数就直接输出1。对于一个非素数,如果是偶数肯定每次都是减去2,结果就是n/2,如果是一个奇数,那么他的最小素数因子肯定是一个奇数,减去这个奇数肯定是偶数,就同上了.
C
题意:给你一个d,问你是否存在a+b==a*b 保证误差在1e-6范围内
思想:可以变成一个一元二次方程组,然后就可以求出来根,求解即可。或者二分一个结果,判断是否成立。但是对于那个求根公式需要考虑 根号下小于0的情况,特判下哪几种情况即可。
#include<bits/stdc++.h>
using namespace std;
const long double eps = 1e-6;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
long double d;
scanf("%Lf",&d);
if(d==1 || d==2 || d==3)
{
printf("N\n");
continue;
}
long double temp = (d*d-4.0*d);
long double b = (d- sqrt(temp))/2.0;
long double a = d - b;
printf("Y %.12Lf %.12Lf\n",a,b);
}
return 0;
}
D
题意:给你n个点m条边,问你保存k条边,最多有多少个点满足1到所有点的距离等于最短距离。
思想:Dijkstra+堆优化 跑最短路,dfs爆搜k条边即可。spfa据说被疯狂卡掉。我写的麻烦还dfs爆搜了,可以不需要,再求最短路的时候保存也行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
const int INF = 0x3f3f3f3f;
int cnt,k;
int head[maxn];
int vis[maxn];
ll dist[maxn];
vector<int>V;
struct node{
int to;
int valu;
int next;
int id;
}no[maxn*2];
struct edge{
int s;
ll w;
bool operator < (const edge& a) const{ return w>a.w;}
};
void add(int u,int v,int valu,int id)
{
no[cnt].to=v;
no[cnt].next=head[u];
no[cnt].valu=valu;
no[cnt].id=id;
head[u]=cnt++;
}
void Dijkstra()
{
memset(dist,INF,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[1]=0;
priority_queue<edge>q;
q.push(edge{1,0});
while(!q.empty())
{
edge temp = q.top();
q.pop();
if(vis[temp.s])
continue;
vis[temp.s]=1;
for(int i=head[temp.s];i!=-1;i=no[i].next)
{
if(dist[no[i].to] > dist[temp.s] + no[i].valu)
{
dist[no[i].to] = dist[temp.s] + no[i].valu;
q.push(edge{no[i].to,dist[no[i].to]});
}
}
}
}
void dfs(int u)
{
if(k<=0)
return ;
if(vis[u])
return ;
vis[u]=1;
for(int i=head[u];i!=-1;i=no[i].next)
{
if(k<=0)
return ;
if(vis[no[i].to])
continue;
if(dist[no[i].to] == dist[u] + no[i].valu)
{
V.push_back(no[i].id);
k--;
dfs(no[i].to);
}
}
}
int main()
{
cnt=0;
int n,m;
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int u,v,valu;
scanf("%d%d%d",&u,&v,&valu);
add(u,v,valu,i);
add(v,u,valu,i);
}
Dijkstra();
memset(vis,0,sizeof(vis));
dfs(1);
printf("%d\n",int(V.size()));
for(int i=0;i<int(V.size());i++)
{
if(i)
printf(" ");
printf("%d",V[i]);
}
puts("");
return 0;
}
E题
题意:给你n个点n-1条边的数,有m次修改,每次将以Vi所有距离Vi距离小于等于Ki的节点的权值增加Xi,输出m次修改后所有的节点的权值是多少,自己到自己的距离是0.
思想:树状数组维护当前节点对于子树的影响,Vi节点能影响到只有自己的孩子节点,所以对于所有的查询的Vi节点,树状数组维护对于孩子的影响,当节点结束之后在去掉即可。深度最大是3e5,不需要到1e9.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
int cnt;
int head[maxn];
int dep[maxn];
int vis[maxn];
ll ans[maxn];
ll c[maxn];
struct node{
int v;
int next;
}no[maxn*2];
vector<pair<int,ll>>V[maxn];
void add(int u,int v)//建图
{
no[cnt].v=v;
no[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int fa)//深度
{
for(int i=head[u];i!=-1;i=no[i].next)
{
int v = no[i].v;
if(dep[v] || v==fa)
continue;
dep[v]=dep[u]+1;
dfs(v,u);
}
}
void up(int d,ll valu)
{
for(int i=min(d,(int)3e5);i<=3e5;i+=(i&(-i)))
c[i]+=valu;
}
ll qu(int d)
{
ll Ans=0;
for(int i=d;i>0;i-=(i&(-i)))
Ans+=c[i];
return Ans;
}
void dfs1(int u)
{
vis[u]=1;
for(int i=0;i<V[u].size();i++)//先将当前节点所有影响都加上
up(dep[u]+V[u][i].first,V[u][i].second);
ans[u]=qu((int)3e5)-qu(dep[u]-1);//计算下祖先节点对于当前节点的影响
for(int i=head[u];i!=-1;i=no[i].next)//dfs自己的孩子节点
{
int v=no[i].v;
if(vis[v])
continue;
dfs1(v);
}
for(int i=0;i<V[u].size();i++)//影响删掉即可
up(dep[u]+V[u][i].first,-V[u][i].second);
}
int main()
{
int n;
cnt=0;
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dep[1]=1;
dfs(1,0);
int m;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
int u,d;
ll valu;
scanf("%d%d%lld",&u,&d,&valu);
V[u].push_back(make_pair(min(d,(int)3e5),valu));
}
dfs1(1);
for(int i=1;i<=n;i++)
{
if(i>=2)
printf(" ");
printf("%lld",ans[i]);
}
puts("");
return 0;
}