NOI2015
喵喵喵?这题普及组就能切了吧?直接离散后并查集合并相等关系,枚举每个不等关系判断即可.
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
13 const int N=1000007;
14 typedef long long LL;
15 typedef double db;
16 using namespace std;
17 int T,n,fa[N],ls[N],sz;
18
19 template<typename T> void read(T &x) {
20 char ch=getchar(); x=0; T f=1;
21 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
22 if(ch=='-') f=-1,ch=getchar();
23 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
24 }
25
26 struct node {
27 int i,j,e;
28 node(){}
29 node(int i,int j,int e):i(i),j(j),e(e){}
30 }p[N];
31
32 int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); }
33 int lik(int x,int y) {
34 if(find(x)!=find(y)) fa[find(x)]=find(y);
35 }
36
37 int main() {
38 #ifdef DEBUG
39 freopen(".in","r",stdin);
40 freopen(".out","w",stdout);
41 #endif
42 read(T);
43 while(T--) {
44 read(n); sz=0;
45 For(t,1,n) {
46 int i,j,e;
47 read(i); read(j); read(e);
48 ls[++sz]=i; ls[++sz]=j;
49 p[t]=node(i,j,e);
50 }
51 sort(ls+1,ls+sz+1);
52 int tpsz=unique(ls+1,ls+sz+1)-(ls+1);
53 sz=tpsz;
54 For(i,1,sz) fa[i]=i;
55 For(i,1,n) {
56 p[i].i=lower_bound(ls+1,ls+sz+1,p[i].i)-ls;
57 p[i].j=lower_bound(ls+1,ls+sz+1,p[i].j)-ls;
58 if(p[i].e) lik(p[i].i,p[i].j);
59 }
60 int fl=1;
61 For(i,1,n) if(!p[i].e) {
62 int x=p[i].i,y=p[i].j;
63 if(find(x)==find(y)) {
64 fl=0;
65 break;
66 }
67 }
68 if(!fl) puts("NO");
69 else puts("YES");
70 }
71 return 0;
72 }
73 /*
74 2
75 2
76 1 2 1
77 1 2 0
78 2
79 1 2 1
80 2 1 1
81 */
??? 裸的树剖,不知道出题人怎么想的.
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
13 const int N=100007;
14 typedef long long LL;
15 typedef double db;
16 using namespace std;
17 int n,q;
18 char o[20];
19
20 template<typename T> void read(T &x) {
21 char ch=getchar(); x=0; T f=1;
22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
23 if(ch=='-') f=-1,ch=getchar();
24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
25 }
26
27 int sg[N<<2],lz[N<<2];
28 #define lc x<<1
29 #define rc ((x<<1)|1)
30 #define mid ((l+r)>>1)
31 void add_it(int x,int len,int v) {
32 if(v==1) sg[x]=len; else sg[x]=0; lz[x]=v;
33 }
34
35 void down(int x,int l_len,int r_len) {
36 if(!lz[x]) return;
37 if(l_len) add_it(lc,l_len,lz[x]);
38 if(r_len) add_it(rc,r_len,lz[x]);
39 lz[x]=0;
40 }
41
42 void update(int x,int l,int r,int ql,int qr,int v) {
43 if(l>=ql&&r<=qr) {
44 add_it(x,r-l+1,v); return;
45 }
46 down(x,mid-l+1,r-mid);
47 if(ql<=mid) update(lc,l,mid,ql,qr,v);
48 if(qr>mid) update(rc,mid+1,r,ql,qr,v);
49 sg[x]=sg[lc]+sg[rc];
50 }
51
52 int qry(int x,int l,int r,int ql,int qr) {
53 if(l>=ql&&r<=qr) return sg[x];
54 down(x,mid-l+1,r-mid);
55 if(qr<=mid) return qry(lc,l,mid,ql,qr);
56 if(ql>mid) return qry(rc,mid+1,r,ql,qr);
57 return qry(lc,l,mid,ql,qr)+qry(rc,mid+1,r,ql,qr);
58 }
59
60 int ecnt,fir[N],nxt[N],to[N];
61 void add(int u,int v) {
62 nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
63 }
64
65 int sz[N],R[N],f[N];
66 void dfs(int x,int fa) {
67 f[x]=fa; sz[x]=1; R[x]=R[fa]+1;
68 for(int i=fir[x];i;i=nxt[i]) {
69 dfs(to[i],x);
70 sz[x]+=sz[to[i]];
71 }
72 }
73
74 int top[N],dfn[N],low[N],tid[N],dfs_clock;
75 void DFS(int x,int Top) {
76 top[x]=Top;
77 dfn[x]=++dfs_clock;
78 tid[dfn[x]]=x;
79 int mxson=0;
80 for(int i=fir[x];i;i=nxt[i]) if(!mxson||sz[mxson]<sz[to[i]]) mxson=to[i];
81 if(mxson) DFS(mxson,Top);
82 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=mxson) DFS(to[i],to[i]);
83 low[x]=dfs_clock;
84 }
85
86 int schange(int x,int y,int v) {
87 while(top[x]!=top[y]) {
88 if(R[top[x]]<R[top[y]]) swap(x,y);
89 update(1,1,n,dfn[top[x]],dfn[x],v);
90 x=f[top[x]];
91 }
92 if(dfn[x]>dfn[y]) swap(x,y);
93 update(1,1,n,dfn[x],dfn[y],v);
94 }
95
96 int sqry(int x,int y) {
97 int rs=0;
98 while(top[x]!=top[y]) {
99 if(R[top[x]]<R[top[y]]) swap(x,y);
100 rs+=qry(1,1,n,dfn[top[x]],dfn[x]);
101 x=f[top[x]];
102 }
103 if(dfn[x]>dfn[y]) swap(x,y);
104 rs+=qry(1,1,n,dfn[x],dfn[y]);
105 return rs;
106 }
107
108 int main() {
109 #ifdef DEBUG
110 freopen(".in","r",stdin);
111 freopen(".out","w",stdout);
112 #endif
113 read(n);
114 For(i,2,n) {
115 int fa; read(fa);
116 fa++; add(fa,i);
117 }
118 dfs(1,0);
119 DFS(1,1);
120 update(1,1,n,1,n,1);
121 read(q);
122 For(ti,1,q) {
123 int x;
124 scanf("%s",o);
125 read(x); x++;
126 if(o[0]=='i') {
127 printf("%d\n",sqry(1,x));
128 schange(1,x,-1);
129 }
130 else {
131 printf("%d\n",sz[x]-qry(1,1,n,dfn[x],low[x]));
132 update(1,1,n,dfn[x],low[x],1);
133 }
134 }
135 return 0;
136 }
容易想到状压dp,小于sqrtn的素因子只有8个,每个数大于sqrtn的素因子仅1个,按这个素因子把数分成不相干的若干类.每一类只能一个人选.
然后就不知道怎么做了.
可能从30分暴力开始想容易想到一点.
30分数据n<=30,那么状压所有素因子,
f[i][j]表示第1个人选了i这些因子,第2个人选了j这些因子的方案数.
n<=500时
对于仅含有小于sqrtn的素因子的数可以和30分一样状压dp.
对于含有大于sqrtn的素因子的数,相互直接互不影响,那么分成若干组分别dp就好了.
每一组的dp中,g[0/1][i][j]表示这一组由第0/1个人选的方案数.
每一组的初值g[0][i][j]=g[1][i][j]=f[i][j]
最后答案f[i][j]=g[0][i][j]+g[1][i][j]-f[i][j](减去这一组两个人都啥都没选)
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
13 const int N=259;
14 typedef long long LL;
15 typedef double db;
16 using namespace std;
17 int n,mod,p[150],sz,ok[507],allin[507];
18 LL f[N][N],g[2][N][N],ans;
19
20 template<typename T> void read(T &x) {
21 char ch=getchar(); x=0; T f=1;
22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
23 if(ch=='-') f=-1,ch=getchar();
24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
25 }
26
27 int main() {
28 #ifdef DEBUG
29 freopen(".in","r",stdin);
30 freopen(".out","w",stdout);
31 #endif
32 read(n); read(mod);
33 For(i,2,n) {
34 int fl=1;
35 For(j,2,i-1) if(i%j==0) {
36 fl=0; break;
37 }
38 if(fl) {
39 p[++p[0]]=i;
40 if(i*i<=n) sz++;
41 }
42 }
43 For(i,2,n) {
44 int tp=i;
45 For(j,1,sz) if(tp%p[j]==0) {
46 ok[i]|=(1<<j-1);
47 while(tp%p[j]==0) tp/=p[j];
48 }
49 if(tp==1) allin[i]=1;
50 }
51 f[0][0]=1;
52 int nn=(1<<sz)-1;
53 For(x,2,n) if(allin[x]) {
54 Rep(i,nn,0) Rep(j,nn,0) if(f[i][j]) {
55 if(!(i&ok[x])) (f[i][j|ok[x]]+=f[i][j])%=mod;
56 if(!(j&ok[x])) (f[i|ok[x]][j]+=f[i][j])%=mod;
57 }
58 }
59 For(id,sz+1,p[0]) {
60 For(i,0,nn) For(j,0,nn) g[0][i][j]=g[1][i][j]=f[i][j];
61 for(int x=p[id];x<=n;x+=p[id])
62 Rep(i,nn,0) Rep(j,nn,0) {
63 if(!(i&ok[x])) (g[1][i][j|ok[x]]+=g[1][i][j])%=mod;
64 if(!(j&ok[x])) (g[0][i|ok[x]][j]+=g[0][i][j])%=mod;
65 }
66 For(i,0,nn) For(j,0,nn) f[i][j]=(g[0][i][j]+g[1][i][j]-f[i][j]+mod)%mod;
67 }
68 For(i,0,nn) For(j,0,nn) (ans+=f[i][j])%=mod;
69 printf("%lld\n",ans);
70 return 0;
71 }
感觉是树上贪心乱搞.
然后得知有一种叫哈夫曼树的奥妙的玩意.
哈夫曼树:
一些叶子有权值,一颗树的权证为所有叶子的权值乘以叶子的深度的和,求权值最小的树.一般是二叉的.
先把所有叶子看成一颗单独的树,每次取出权值最小的两个叶子合并,合并后的权值为两个叶子的权值和.
到这道题上,就是求一个k叉的哈夫曼树.那么每次取出权值最小的k个树来合并.
当(n-1)%(k-1)不等于0时,需补上一些权值为0的叶子再做.
要使得深度最大的叶子最小,每次合并时存在权值相同的树时,规定深度小的树权值为小即可.
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
13 const int N=200007;
14 typedef long long LL;
15 typedef double db;
16 using namespace std;
17 LL n,k,w[N],anstot,ansh;
18
19 template<typename T> void read(T &x) {
20 char ch=getchar(); x=0; T f=1;
21 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
22 if(ch=='-') f=-1,ch=getchar();
23 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
24 }
25
26 #define pr pair<LL,LL>
27 #define fi first
28 #define se second
29 pr p[N];
30 priority_queue<pr,vector<pr>,greater<pr> >que;
31 void build(int n) {
32 For(i,1,n) que.push(p[i]);
33 for(;;) {
34 pr y;
35 LL W=0,H=0;
36 For(i,1,k) {
37 pr x=que.top();
38 W+=x.fi;
39 H=max(H,x.se+1);
40 que.pop();
41 }
42 y.fi=W; y.se=H;
43 anstot+=W;
44 if(que.empty()) {
45 ansh=y.se;
46 break;
47 }
48 que.push(y);
49 }
50 }
51
52 int main() {
53 #ifdef DEBUG
54 freopen(".in","r",stdin);
55 freopen(".out","w",stdout);
56 #endif
57 read(n); read(k);
58 For(i,1,n) read(w[i]);
59 while((n-1)%(k-1)) n++;
60 For(i,1,n) { p[i].fi=w[i]; p[i].se=0; }
61 build(n);
62 printf("%lld %lld\n",anstot,ansh);
63 return 0;
64 }
T5品酒大会