hihocoder #1073 : 光棍节
描述
尽管付出了种种努力,jzp还是得过光棍节。
jzp非常不爽,但也无能为力,只能够哀叹起来他的命运。他想到了一位长者的人生经验:“人的一生,不光要靠自我奋斗,也要考虑历史的进程”。
他终于明白自己只是时运不济,所以又继续开始努力。终于在圣诞节当天把到了妹子。
jzp从此过上了快乐的现充生活,在圣诞节当天,他还和妹子玩起了有趣的游戏:
jzp的家里有一棵非常大的圣诞树,可以看成是一个n个点的无向联通无环图。每个点上都有一个正整数,JZP和妹子每次都会选择树上的一条路径,
这条路径的权值被定义为路径上所有点上数的最大公约数,JZP可以得到这个权值的分数。
JZP玩了一会儿有点腻了,他想知道对于每种可能的权值x,权值为x的不同路径的数量(a到b的路径和b到a的路径算作一种,a到a自身也算作一条路径。)
解题报告:
用时2h30min,N TLE
这题不难,直接暴力点分,复杂度可以证明是对的,因为从一个点下去,gcd只有可以是它的约数,所以是\(\sqrt n\)的,所以直接去重之后两重循环枚举,复杂度是\(O(n)\)的,所以复杂度是对的。但是本人太渣,点分都可以写错,找重心的数组一直没清空(那么居然是0.7s是怎么回事?)然后一交就TLE,还以为是常数太大,就一直在压,浪费了许久,写了两个代码,一个是所有方案-不合法的,另一个是用vector维护已经处理过的子树的gcd,处理完当前子树后,在处理另一个子树直接用当前子树的每一个gcd和vector里的元素匹配.
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,val[N],head[N],num=0,nxt[N<<1],to[N<<1],sum;
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
bool vis[N];int sz[N],root=0,son[N]={N};
il int gi(){
RG int str=0;RG char ch=getchar();
while(ch>'9' || ch<'0')ch=getchar();
while(ch>='0' && ch<='9')
str=(str<<1)+(str<<3)+ch-48,ch=getchar();
return str;
}
il void getroot(int x,int last){
int u;sz[x]=1;son[x]=0;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==last || vis[u])continue;
getroot(u,x);
sz[x]+=sz[u];son[x]=Max(son[x],sz[u]);
}
son[x]=Max(son[x],sum-sz[x]);
if(son[x]<son[root])root=x;
}
il int gcd(int x,int y){
int c;while(x%y){c=y;y=x%y;x=c;}
return y;
}
vector<int>q,s;ll t[N],ton[N];
void count(int x){
int szz=q.size(),gc;
for(int i=0;i<szz;i++){
gc=gcd(q[i],x);
t[gc]+=ton[q[i]];
}
}
int app[N];
il void calc(int x,int last,int g){
int u;
t[g]++;count(g);
if(!app[g])s.push_back(g);app[g]++;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==last || vis[u])continue;
if(g!=1)calc(u,x,gcd(val[u],g));
else calc(u,x,1);
}
}
il void solve(int x){
int u,szz;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(vis[u])continue;
calc(u,x,gcd(val[u],val[x]));
szz=s.size();
for(int j=0;j<szz;j++){
if(!ton[s[j]])q.push_back(s[j]);
ton[s[j]]+=app[s[j]];app[s[j]]=0;
}
s.clear();
}szz=q.size();
for(int i=0;i<szz;i++)ton[q[i]]=0;
q.clear();
}
il void dfs(int x){
int u;vis[x]=true;solve(x);
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(vis[u])continue;
root=0;sum=sz[u];getroot(u,x);
dfs(root);
}
}
void work()
{
int x,y,lim=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
val[i]=gi();
lim=Max(lim,val[i]);
t[val[i]]++;
}
for(int i=1;i<n;i++){
x=gi();y=gi();
link(x,y);link(y,x);
}
sum=n;root=0;getroot(1,1);
dfs(root);
for(int i=1;i<=lim;i++)
if(t[i])printf("%d %lld\n",i,t[i]);
}
int main()
{
work();
return 0;
}
再是原来写的,清空数组后也能过
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,val[N],head[N],num=0,nxt[N<<1],to[N<<1],sum;
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
bool vis[N];int sz[N],root=0,son[N]={N};
il int gi(){
RG int str=0;RG char ch=getchar();
while(ch>'9' || ch<'0')ch=getchar();
while(ch>='0' && ch<='9')
str=(str<<1)+(str<<3)+ch-48,ch=getchar();
return str;
}
il void getroot(int x,int last){
int u;sz[x]=1;son[x]=0;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==last || vis[u])continue;
getroot(u,x);
sz[x]+=sz[u];son[x]=Max(son[x],sz[u]);
}
son[x]=Max(son[x],sum-sz[x]);
if(son[x]<son[root])root=x;
}
il int gcd(int x,int y){
int c;while(x%y){c=y;y=x%y;x=c;}
return y;
}
struct node{
int x;ll cnt;
bool operator <(const node &Pr)const{return x<Pr.x;}
}q[N];
int top=0;bool flag=false;
il void calc(int x,int last,int g){
int u;
if(g==1 && flag){q[++top].x=1;q[top].cnt=sz[x];return ;}
if(top && q[top].x==g)q[top].cnt++;
else q[++top].x=g,q[top].cnt=1;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==last || vis[u])continue;
if(g!=1)calc(u,x,gcd(val[u],g));
else calc(u,x,1);
}
}
ll t[N];
il void solve(int x,int op,int sta){
top=0;calc(x,x,sta);
int Yut=top;top=1;
sort(q+1,q+Yut+1);
RG int i,j;
for(i=2;i<=Yut;i++){
if(q[i].x==q[top].x)q[top].cnt+=q[i].cnt;
else q[++top]=q[i];
}
int tmp;
for(i=1;i<=top;i++){
t[q[i].x]+=q[i].cnt*(q[i].cnt-1)*op>>1;
for(j=i+1;j<=top;j++){
tmp=gcd(q[i].x,q[j].x);
t[tmp]+=q[i].cnt*q[j].cnt*op;
}
}
}
il void dfs(int x){
int u;vis[x]=true;
flag=false;solve(x,1,val[x]);
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(vis[u])continue;
root=0;sum=sz[u];getroot(u,x);
flag=true;solve(u,-1,gcd(val[x],val[u]));
dfs(root);
}
}
void work()
{
int x,y,lim=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
val[i]=gi();
lim=Max(lim,val[i]);
t[val[i]]++;
}
for(int i=1;i<n;i++){
x=gi();y=gi();
link(x,y);link(y,x);
}
sum=n;root=0;getroot(1,1);
dfs(root);
for(int i=1;i<=lim;i++)
if(t[i])printf("%d %lld\n",i,t[i]);
}
int main()
{
work();
return 0;
}
hihocoder #1073 : 光棍节的更多相关文章
- 11.11光棍节工作心得——github/MVP
11.11光棍节工作心得 1.根据scrum meeting thirdday中前辈的指导进行学习 我在博客中贴了链接,竟然TrackBack引来了原博主,
- hiho 光棍节
描述 尽管付出了种种努力,jzp还是得过光棍节. jzp非常不爽,但也无能为力,只能够哀叹起来他的命运.他想到了一位长者的人生经验:“人的一生,不光要靠自我奋斗,也要考虑历史的进程”. 他终于明白自己 ...
- ABBYY FineReader去他的光棍节,我要我的双十一
今天就是双十一,全民剁手的双十一,一年仅一次的双十一,不只是半价的双十一.....此时此刻,多少钱拿起手机在疯狂购物,又有多少人死守着电脑,不敢怠慢一丁点机会,买着买着购物车就空了,然后才发现,咦!超 ...
- 光棍节程序员闯关秀writeup
答题链接https://1111.segmentfault.com/ 第一关 首先当然是右键查看源码啊 点击链接进入下一关 第二关 还是老样子,右键查看源码 这个key是要放在URL链接里敲回车的 第 ...
- zznu 1073: 海军节上的鸣炮声计算
这是个一不留神就会出错的题目,首先大家可以想到在同一时间可能会有多个炮同时发射,不过观众只能听到一响,所以需要注意! 而且刚开始的时候所有的船都会发射一发,输入的a, b, c,都是时间间隔,
- 11月11日光棍节考试总结hhh
好吧,第一题字符串裸栈就能A 第二题字典序没调完,先写的第一题和第三题暴力,第二题读题感觉自己不会写,其实也能写出来,浪费了好多时间 第三题DP大概是写的暴力,原本可以搞到20分,要交的时候发现自己少 ...
- NYOJ-451-光棍节的快乐
光棍节的快乐 时间限制:1000 ms | 内存限制:65535 KB 难度: 描写叙述 光棍们,今天是光棍节.聪明的NS想到了一个活动来丰富这个光棍节. 规则例如以下: 每一个光棍在一个纸条上写 ...
- “老坛泡新菜”:SOD MVVM框架,让WinForms焕发新春
火热的MVVM框架 最近几年最热门的技术之一就是前端技术了,各种前端框架,前端标准和前端设计风格层出不穷,而在众多前端框架中具有MVC,MVVM功能的框架成为耀眼新星,比如GitHub关注度很高的Vu ...
- quartz CronExpression表达式
一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素.按顺序依次为1.秒(0~59)2.分钟(0~59)3.小时(0~23)4.天(月)(0~31,但是你需要考虑你月的天数)5.月(0~11 ...
随机推荐
- 转git取消commit
如果不小心commit了一个不需要commit的文件,可以对其进行撤销. 先使用git log 查看 commit日志 commit 422bc088a7d6c5429f1d0760d008d8 ...
- Windows下编译SDL
Windows下编译SDL的理由我就不多说了,无论用VS来编译或调试SDL库都是很方便的.而且SDL源代码中也包含了VC工程,你所要做的只是解压VC工程,进行适当的配置,然后编译.调试. 编译SDL大 ...
- Scrum 冲刺 第四日
目录 要求 项目链接 燃尽图 问题 今日任务 明日计划 成员贡献量 小组会议 要求 各个成员今日完成的任务(如果完成的任务为开发或测试任务,需给出对应的Github代码签入记录截图:如果完成的任务为调 ...
- 201421123042 《Java程序设计》第7周学习总结
1. 本周学习总结 1.1 思维导图:Java图形界面总结 2.书面作业 1. GUI中的事件处理 1.1 写出事件处理模型中最重要的几个关键词. 事件源 事件对象 事件监听器 事件适合配器 1.2 ...
- PAT1048. Find Coins(01背包问题动态规划解法)
问题描述: Eva loves to collect coins from all over the universe, including some other planets like Mars. ...
- Spark学习笔记之RDD中的Transformation和Action函数
总算可以开始写第一篇技术博客了,就从学习Spark开始吧.之前阅读了很多关于Spark的文章,对Spark的工作机制及编程模型有了一定了解,下面把Spark中对RDD的常用操作函数做一下总结,以pys ...
- 获取apk项目的MD5值和SHA1值
一些可说可不说的话: * 以前有一个更简单的方法,在as的右边工具栏的 gradle 面板中可以很方便的获取到: * 上次用也是在2年前,时间长了给忘记了,不过我记得我当时写了笔记,这会笔记不在身边, ...
- RSA的公钥、私钥
一.举个例子 1.发消息 用对方的公钥给对方发消息 2.发公告 发公告的时候,用自己的私钥形成签名! 二.加密和签名 RSA的公钥.私钥是互相对应的,RSA会生成两个密钥,你可以把任何一个用于公钥,然 ...
- JDBC学习笔记 day1
JDBC的基本概念: JDBC就是java database connectivity,即java数据库连接. JDBC主要完成的几个任务分别为 与数据库建立一个连接 向数据库发送SQL语句 处理数据 ...
- python实现 字符串匹配函数
通配符是 shell 命令中的重要功能,? 表示匹配任意 1 个字符,*表示匹配 0 个或多个字符.请使用你熟悉的编程语言实现一个字符串匹配函数,支持 ? 和 * 通配符.如 "a?cd*d ...