[cf1240F]Football

(事实上,总是可以让每一场都比,因此$w_{i}$并没有意义)

当$k=2$时,有如下做法——

新建一个点,向所有奇度数的点连边,并对得到的图求欧拉回路,那么只需要将欧拉回路上的边交替染色,即可保证$|s_{i,1}-s_{i,2}|\le 1$(路径长度为奇数时的起点),去掉新建的点后仍有$|s_{i,1}-s_{i,2}|\le 2$,也即合法

当$k$任意时,有如下做法——

随机一组方案,找到两种不合法的颜色$a$和$b$(即$\exists i,|s_{i,a}-s_{i,b}|\ge 3$),将图中颜色为$a$或$b$的边用$k=2$时的方式重新染色,重复此过程直至找到不到$a$和$b$,显然此时即合法

考虑这一做法的复杂度(和有限性),令$C=\sum_{i=1}^{n}\sum_{j=1}^{k}s_{i,j}^{2}$,考虑调整对$C$的影响:假设调整后的为$s'_{i,j}$,代入该式即使得$C$减少$\sum_{i=1}^{n}(s_{i,a}^{2}+s_{i,b}^{2}-s{'}_{i,a}^{2}-s{'}_{i,b}^{2})$

由于$s_{i,a}+s_{i,b}$固定,因此$|s'_{i,a}-s'_{i,b}|\le 1$时必然取到最小,即每一项该值均非负

另一方面,对于$|s_{i,a}-s_{i,b}|\ge 3$的位置,该值至少为4,也即$C$至少减少4

同时$C$非负,因此轮数为$o(C)$,其实际意义可以看作选择两条边满足有公共点且颜色相同,那么先确定其中一条边,由于没有重边,显然另一条边至多有$o(n)$种,即$C\le nm$

另外,每一轮调整复杂度为$o(n\log k+m)$(找$x,y$和求欧拉回路)

时间复杂度为$o(n^{2}m\log k+nm^{2})$,由于跑不满,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 105
 4 #define M 1005
 5 #define fi first
 6 #define se second
 7 struct Edge{
 8     int nex,to;
 9 }edge[N+M<<1];
10 pair<int,int>e[M];
11 multiset<int>S[N];
12 int n,m,t,E,P,head[N],vis[N+M],ans[M],sum[N][M];
13 void add(int x,int y){
14     edge[E].nex=head[x];
15     edge[E].to=y;
16     head[x]=E++;
17 }
18 void dfs(int k){
19     for(int i=head[k];i!=-1;i=edge[i].nex)
20         if (vis[i>>1]<0){
21             vis[i>>1]=0;
22             dfs(edge[i].to);
23             vis[i>>1]=P,P^=1;
24         }
25 }
26 int main(){
27     srand(time(0));
28     scanf("%d%d%d",&n,&m,&t);
29     for(int i=1;i<=n;i++)scanf("%*d");
30     for(int i=1;i<=m;i++)scanf("%d%d",&e[i].fi,&e[i].se);
31     for(int i=1;i<=m;i++){
32         ans[i]=rand()%t+1;
33         sum[e[i].fi][ans[i]]++;
34         sum[e[i].se][ans[i]]++;
35     }
36     for(int i=1;i<=n;i++)
37         for(int j=1;j<=t;j++)S[i].insert(sum[i][j]);
38     while (1){
39         int x=0,y=0;
40         for(int i=1;i<=n;i++)
41             if ((*--S[i].end())-(*S[i].begin())>=3){
42                 x=y=1;
43                 for(int j=2;j<=t;j++){
44                     if (sum[i][j]>sum[i][x])x=j;
45                     if (sum[i][j]<sum[i][y])y=j;
46                 }
47                 break;
48             }
49         if ((!x)&&(!y))break;
50         E=P=0;
51         memset(head,-1,sizeof(head));
52         for(int i=1;i<=m;i++)
53             if ((ans[i]==x)||(ans[i]==y)){
54                 add(e[i].fi,e[i].se);
55                 add(e[i].se,e[i].fi);
56             }
57         for(int i=1;i<=n;i++)
58             if ((sum[i][x]+sum[i][y])&1)add(0,i),add(i,0);
59         memset(vis,-1,sizeof(vis));
60         for(int i=1;i<=n;i++)dfs(i);
61         for(int i=1;i<=n;i++){
62             S[i].erase(S[i].find(sum[i][x]));
63             S[i].erase(S[i].find(sum[i][y]));
64             sum[i][x]=sum[i][y]=0;
65         }
66         for(int i=1,j=0;i<=m;i++)
67             if ((ans[i]==x)||(ans[i]==y)){
68                 if (vis[j])ans[i]=x;
69                 else ans[i]=y;
70                 sum[e[i].fi][ans[i]]++;
71                 sum[e[i].se][ans[i]]++;
72                 j++;
73             }
74         for(int i=1;i<=n;i++){
75             S[i].insert(sum[i][x]);
76             S[i].insert(sum[i][y]);
77         }
78     }
79     for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
80     return 0;
81 }
View Code

 

posted @ 2021-09-30 10:27  PYWBKTDA  阅读(52)  评论(0编辑  收藏  举报