THUSC2017 Day1题解

巧克力

题目描述

“人生就像一盒巧克力,你永远不知道吃到的下一块是什么味道。”

明明收到了一大块巧克力,里面有若干小块,排成n行m列。每一小块都有自己特别的图案ci,j,它们有的是海星,有的是贝壳,有的是海螺......其中还有一些因为挤压,已经分辨不出是什么图案了。明明给每一小块巧克力标上了一个美味值\(a_{i,j }( 0 \le a_{i,j} \le 10^6 )\),这个值越大,表示这一小块巧克力越美味。

正当明明咽了咽口水,准备享用美味时,舟舟神奇地出现了。看到舟舟恳求的目光,明明决定从中选出一些小块与舟舟一同分享。

舟舟希望这些被选出的巧克力是连通的(两块巧克力连通当且仅当他们有公共边),而且这些巧克力要包含至少\(k ( 1 \le k \le 5 )\)种。而那些被挤压过的巧克力则是不能被选中的。

明明想满足舟舟的愿望,但他又有点“抠”,想将美味尽可能多地留给自己。所以明明希望选出的巧克力块数能够尽可能地少。如果在选出的块数最少的前提下,美味值的中位数(我们定义\(n\)个数的中位数为第\(⌊\frac{n+1}{2}⌋\)小的数)能够达到最小就更好了。

你能帮帮明明吗?

输入格式

从标准输入读入数据。

每个测试点包含多组测试数据。

输入第一行包含一个正整数 \(T (1 \le T \le 5)\),表示测试数据组数。

对于每组测试数据:

输入第一行包含三个正整数\(n,m\)和\(k\);

接下来\(n\)行,每行\(m\)个整数,表示每小块的图案\(c_{i,j}\)。若\(c_{i,j}=−1\)表示这一小块受到过挤压,不能被选中;

接下来\(n\)行,每行\(m\)个整数,表示每个小块的美味值\(a_{i,j}\)。

输出格式

输出到标准输出。

输出共包括\(T\)行,每行包含两个整数,用空格隔开,即最少的块数和最小的美味值中位数。

若对于某组测试数据,不存在任意一种合法的选取方案,请在对应行输出两个\(−1\)。

数据范围

\(n \times m \le 233\)

题解

我们发现这个至少有\(k\)种颜色非常不好处理,我们就把所有颜色随机分到\(k\)个块里,只要每个块的颜色都被取到,那就说明至少有\(k\)个颜色

直接二分中位数,每次随机颜色块,做一遍斯坦纳树即可。这里有个技巧就是把大于中位数的赋值成\(1001\),其他的赋成的\(999\),设求出来的最小值为\(Min\),则最少块数为\(\frac{Min+500}{1000}\),同时也可以通过与答案\(\times 1000\)的大小比较来check中位数

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define REP(i,st,ed) for(register int i=st,i##end=ed;i<=i##end;++i)
  4. #define DREP(i,st,ed) for(register int i=st,i##end=ed;i>=i##end;--i)
  5. typedef long long ll;
  6. template<typename T>inline bool chkmin(T &x,T y){return (y<x)?(x=y,1):0;}
  7. template<typename T>inline bool chkmax(T &x,T y){return (y>x)?(x=y,1):0;}
  8. inline int read(){
  9. int x;
  10. char c;
  11. int f=1;
  12. while((c=getchar())!='-' && (c>'9' || c<'0'));
  13. if(c=='-') f=-1,c=getchar();
  14. x=c^'0';
  15. while((c=getchar())>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0');
  16. return x*f;
  17. }
  18. inline ll readll(){
  19. ll x;
  20. char c;
  21. int f=1;
  22. while((c=getchar())!='-' && (c>'9' || c<'0'));
  23. if(c=='-') f=-1,c=getchar();
  24. x=c^'0';
  25. while((c=getchar())>='0' && c<='9') x=(x<<1ll)+(x<<3ll)+(c^'0');
  26. return x*f;
  27. }
  28. const int maxn=233+10,inf=0x3f3f3f3f;
  29. int N,id[maxn][maxn],dp[1<<5][maxn],vis[1<<5][maxn];
  30. int col[maxn],c[maxn][maxn],val[maxn],a[maxn][maxn];
  31. int idx[maxn],idx_cnt,Min;
  32. int num[maxn],k;
  33. int Begin[maxn],Next[maxn*10],to[maxn*10],e;
  34. int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
  35. inline void add_edge(int x,int y){
  36. to[++e]=y;
  37. Next[e]=Begin[x];
  38. Begin[x]=e;
  39. }
  40. struct point{
  41. int x,y;
  42. };
  43. inline void spfa(int Nw){
  44. queue<point> q;
  45. REP(i,1,N) vis[Nw][i]=1,q.push((point){Nw,i});
  46. while(!q.empty()){
  47. point u=q.front();q.pop();
  48. for(int i=Begin[u.y];i;i=Next[i]){
  49. point v;
  50. v.y=to[i],v.x=u.x;
  51. if(col[to[i]]==-1) continue;
  52. v.x|=(1<<col[to[i]]);
  53. if(chkmin(dp[v.x][v.y],dp[u.x][u.y]+val[to[i]]))
  54. if(!vis[v.x][v.y]){
  55. vis[v.x][v.y]=1;
  56. q.push(v);
  57. }
  58. vis[u.x][u.y]=0;
  59. }
  60. }
  61. }
  62. inline void Steiner_tree(){
  63. memset(dp,inf,sizeof(dp));
  64. REP(i,1,N)
  65. if(col[i]!=-1) dp[1<<col[i]][i]=val[i];
  66. REP(i,1,(1<<k)-1){
  67. REP(j,1,N){
  68. int x,y;
  69. if(col[j]!=-1) y=(1<<col[j]);
  70. else y=0;
  71. if(!y) continue;
  72. if((i&y)!=y) continue;
  73. x=(i^y);
  74. for(int u=x;u;u=(u-1)&x) chkmin(dp[i][j],dp[u|y][j]+dp[(u^x)|y][j]-val[j]);
  75. }
  76. spfa(i);
  77. REP(j,1,N) for(int u=(i-1)&i;u;u=(u-1)&i) chkmin(dp[u][j],dp[i][j]);
  78. }
  79. REP(i,1,N) chkmin(Min,dp[(1<<k)-1][i]);
  80. }
  81. int main(){
  82. #ifndef ONLINE_JUDGE
  83. freopen("a.in","r",stdin);
  84. freopen("a.out","w",stdout);
  85. #endif
  86. srand(234111);
  87. int T=read();
  88. while(T--){
  89. int n=read(),m=read();
  90. k=read();
  91. N=idx_cnt=0;
  92. REP(i,1,n) REP(j,1,m) id[i][j]=++N;
  93. REP(i,1,n) REP(j,1,m) c[i][j]=read();
  94. REP(i,1,n) REP(j,1,m) a[i][j]=read(),idx[++idx_cnt]=a[i][j];
  95. e=0;
  96. REP(i,1,N) Begin[i]=0;
  97. sort(idx+1,idx+idx_cnt+1);
  98. idx_cnt=unique(idx+1,idx+idx_cnt+1)-idx-1;
  99. REP(i,1,n) REP(j,1,m) REP(x,0,3){
  100. int u=i+dir[x][0],v=j+dir[x][1];
  101. if(u>n || u<1 || v>m || v<1) continue;
  102. // cout<<i<<' '<<j<<' '<<u<<' '<<v<<endl;
  103. add_edge(id[i][j],id[u][v]);
  104. }
  105. int L=1,R=idx_cnt;
  106. int ans=inf;
  107. while(L<=R){
  108. int Mid=(L+R)>>1;
  109. Min=inf;
  110. REP(i,1,n) REP(j,1,m)
  111. if(a[i][j]>idx[Mid]) val[id[i][j]]=1001;
  112. else val[id[i][j]]=999;
  113. REP(_,1,200){
  114. REP(i,1,N) num[i]=rand()%k;
  115. REP(i,1,n) REP(j,1,m)
  116. if(c[i][j]==-1) col[id[i][j]]=-1;
  117. else col[id[i][j]]=num[c[i][j]];
  118. Steiner_tree();
  119. }
  120. ans=(Min+500)/1000;
  121. // cerr<<Mid<<' '<<Min<<endl;
  122. if(Min<=ans*1000) R=Mid-1;
  123. else L=Mid+1;
  124. }
  125. if(ans>N) printf("-1\n");
  126. else printf("%d %d\n",ans,idx[R+1]);
  127. }
  128. return 0;
  129. }

杜老师

题目描述

杜老师可是要打\(+\infty\)年\(World Final\)的男人,虽然规则不允许,但是可以改啊!

但是今年\(WF\)跟\(THUSC\)的时间这么近,所以他造了一个\(idea\)就扔下不管了……

给定\(L,R\),求从\(L\)到\(R\)的这\(R−L+1\)个数中能选出多少个不同的子集,满足子集中所有的数的乘积是一个完全平方数。特别地,空集也算一种选法,定义其乘积为\(1\)。

由于杜老师忙于跟陈老师和鏼老师一起打ACM竞赛,所以,你能帮帮杜老师写写标算吗?

输入格式

从标准输入读入数据。

每个测试点包含多组测试数据。

输入第一行包含一个正整数 \(T (1 \le T \le 100)\),表示测试数据组数。

接下来\(T\)行,第\(i+1\)行两个正整数\(L_i,R_i\)表示第 i 组测试数据的 \(L,R\) ,保证\(1 \le L_i \le R_i \le 10^7\)。

输出格式

输出到标准输出。

输出\(T\)行,每行一个非负整数,表示一共可以选出多少个满足条件的子集,答案对\(998244353\)取模。

数据范围

\(R_i \le 10^7, \sum R_i-L_i \le 6 \times 10 ^7\)

题解

首先很容易想到分解质因数,然后对于每一个数\(x\),可以变成一个二进制数,二进制数的第\(i\)位代表\(x\)包含奇数还是偶数个\(p_i\)的质因子。之后就求出线性基,那么答案即为\(自由元个数2^{自由元个数}\).这样可以拿到\(50\)分

然后我一开始在看这道题的时候,我发现了两个结论:

1.当\(\frac{R}{L} \ge p_i\)时\(i\)这一位一定有基

2.当\(p_i > \sqrt{R}\)是\(i\)这一位一定有基

我一开始判掉两个结论,然后剩下的直接暴力高斯消元有\(80\)分

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define REP(i,st,ed) for(register int i=st,i##end=ed;i<=i##end;++i)
  4. #define DREP(i,st,ed) for(register int i=st,i##end=ed;i>=i##end;--i)
  5. typedef long long ll;
  6. template<typename T>inline bool chkmin(T &x,T y){return (y<x)?(x=y,1):0;}
  7. template<typename T>inline bool chkmax(T &x,T y){return (y>x)?(x=y,1):0;}
  8. inline int read(){
  9. int x;
  10. char c;
  11. int f=1;
  12. while((c=getchar())!='-' && (c>'9' || c<'0'));
  13. if(c=='-') f=-1,c=getchar();
  14. x=c^'0';
  15. while((c=getchar())>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0');
  16. return x*f;
  17. }
  18. inline ll readll(){
  19. ll x;
  20. char c;
  21. int f=1;
  22. while((c=getchar())!='-' && (c>'9' || c<'0'));
  23. if(c=='-') f=-1,c=getchar();
  24. x=c^'0';
  25. while((c=getchar())>='0' && c<='9') x=(x<<1ll)+(x<<3ll)+(c^'0');
  26. return x*f;
  27. }
  28. const int maxm=1e7+10,maxn=1000+10,mod=998244353;
  29. int prime[maxm],isprime[maxm],Max[maxm],cnt;
  30. inline void init(int n){
  31. REP(i,2,n){
  32. if(!isprime[i]) prime[++cnt]=i,Max[i]=cnt;
  33. REP(j,1,cnt){
  34. int u=i*prime[j];
  35. if(u>n) break;
  36. isprime[u]=1;
  37. Max[u]=max(Max[i],j);
  38. if(i%prime[j]==0) break;
  39. }
  40. }
  41. }
  42. ll bit[maxn][maxn],a[maxn],num[maxn];
  43. int tmp,tot,All;
  44. bool p[maxn];
  45. int ans,Begin[maxm],to[maxm*10],Next[maxm*10],e;
  46. inline void add_edge(int x,int y){
  47. to[++e]=y;
  48. Next[e]=Begin[x];
  49. Begin[x]=e;
  50. }
  51. inline int ksm(int x,int y){
  52. int res=1;
  53. while(y){
  54. if(y&1) res=(ll)res*x%mod;
  55. y>>=1;
  56. x=(ll)x*x%mod;
  57. }
  58. return res;
  59. }
  60. inline void add(){
  61. REP(i,0,tot) if(a[i/64]&(1ll<<(ll)(i%64))){
  62. if(p[i]){
  63. REP(j,0,tmp) a[j]^=bit[i][j];
  64. }
  65. else{
  66. REP(j,0,tmp) bit[i][j]=a[j];
  67. // cerr<<i<<' '<<All<<endl;
  68. p[i]=1;
  69. --ans;
  70. --All;
  71. break;
  72. }
  73. }
  74. }
  75. int main(){
  76. #ifndef ONLINE_JUDGE
  77. freopen("b.in","r",stdin);
  78. freopen("b.out","w",stdout);
  79. #endif
  80. init(maxm-10);
  81. int T=read();
  82. while(T--){
  83. int L=read(),R=read();
  84. int t1=upper_bound(prime+1,prime+cnt+1,R/L)-prime;
  85. int t2;
  86. for(t2=0;prime[t2+1]*prime[t2+1]<=R;++t2);
  87. int t3=upper_bound(prime+1,prime+cnt+1,R)-prime-1;
  88. REP(i,L,R) Begin[i]=0;
  89. e=0;
  90. ans=(R-L+1);
  91. ans-=t1-1;
  92. // cerr<<t1<<' '<<t2<<' '<<t3<<endl;
  93. REP(i,t1,t2) REP(j,(L-1)/prime[i]+1,R/prime[i]){
  94. int u=j,x=1;
  95. while(u%prime[i]==0) u/=prime[i],x^=1;
  96. if(x) add_edge(prime[i]*j,i-t1);
  97. }
  98. tmp=(t2-t1)/64;
  99. tot=t2-t1;
  100. REP(i,0,tot){
  101. REP(j,0,tmp) bit[i][j]=0;
  102. p[i]=0;
  103. }
  104. All=tot;
  105. REP(i,max(t2+1,t1),t3){
  106. int l=(L-1)/prime[i]+1,r=R/prime[i];
  107. if(l>r) continue;
  108. ans--;
  109. if(All<0) continue;
  110. if(l==r) continue;
  111. REP(j,0,tmp) num[j]=0;
  112. for(int j=Begin[l*prime[i]];j;j=Next[j]) num[to[j]/64]^=(1ll<<(ll)(to[j]%64));
  113. REP(j,l+1,r){
  114. REP(k,0,tmp) a[k]=num[k];
  115. for(int k=Begin[j*prime[i]];k;k=Next[k]) a[to[k]/64]^=(1ll<<(ll)(to[k]%64));
  116. add();
  117. if(All<0) break;
  118. }
  119. }
  120. REP(i,L,R) if(Max[i]<=t2){
  121. if(All<0) break;
  122. REP(j,0,tmp) a[j]=0;
  123. for(int j=Begin[i];j;j=Next[j]) a[to[j]/64]^=(1ll<<(ll)(to[j]%64));
  124. add();
  125. }
  126. printf("%d\n",ksm(2,ans));
  127. }
  128. return 0;
  129. }

正解好迷啊,有个结论,当\(R-L \ge 6000\)时只要区间内出现了这个质因子就一定有基。大于\(6000\)的直接判,剩下的暴力高斯消元。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define REP(i,st,ed) for(register int i=st,i##end=ed;i<=i##end;++i)
  4. #define DREP(i,st,ed) for(register int i=st,i##end=ed;i>=i##end;--i)
  5. typedef long long ll;
  6. template<typename T>inline bool chkmin(T &x,T y){return (y<x)?(x=y,1):0;}
  7. template<typename T>inline bool chkmax(T &x,T y){return (y>x)?(x=y,1):0;}
  8. inline int read(){
  9. int x;
  10. char c;
  11. int f=1;
  12. while((c=getchar())!='-' && (c>'9' || c<'0'));
  13. if(c=='-') f=-1,c=getchar();
  14. x=c^'0';
  15. while((c=getchar())>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0');
  16. return x*f;
  17. }
  18. inline ll readll(){
  19. ll x;
  20. char c;
  21. int f=1;
  22. while((c=getchar())!='-' && (c>'9' || c<'0'));
  23. if(c=='-') f=-1,c=getchar();
  24. x=c^'0';
  25. while((c=getchar())>='0' && c<='9') x=(x<<1ll)+(x<<3ll)+(c^'0');
  26. return x*f;
  27. }
  28. const int maxm=1e7+10,maxn=1000+10,mod=998244353;
  29. int prime[maxm],isprime[maxm],Max[maxm],cnt;
  30. inline void init(int n){
  31. REP(i,2,n){
  32. if(!isprime[i]) prime[++cnt]=i,Max[i]=cnt;
  33. REP(j,1,cnt){
  34. int u=i*prime[j];
  35. if(u>n) break;
  36. isprime[u]=1;
  37. Max[u]=max(Max[i],j);
  38. if(i%prime[j]==0) break;
  39. }
  40. }
  41. }
  42. ll bit[maxn][maxn],a[maxn],num[maxn];
  43. int tmp,tot,All;
  44. bool p[maxn];
  45. int ans,Begin[maxm],to[maxm*10],Next[maxm*10],e;
  46. inline void add_edge(int x,int y){
  47. to[++e]=y;
  48. Next[e]=Begin[x];
  49. Begin[x]=e;
  50. }
  51. inline int ksm(int x,int y){
  52. int res=1;
  53. while(y){
  54. if(y&1) res=(ll)res*x%mod;
  55. y>>=1;
  56. x=(ll)x*x%mod;
  57. }
  58. return res;
  59. }
  60. inline void add(){
  61. REP(i,0,tot) if(a[i/64]&(1ll<<(ll)(i%64))){
  62. if(p[i]){
  63. REP(j,0,tmp) a[j]^=bit[i][j];
  64. }
  65. else{
  66. REP(j,0,tmp) bit[i][j]=a[j];
  67. // cerr<<i<<' '<<All<<endl;
  68. p[i]=1;
  69. --ans;
  70. --All;
  71. break;
  72. }
  73. }
  74. }
  75. int main(){
  76. #ifndef ONLINE_JUDGE
  77. freopen("b.in","r",stdin);
  78. freopen("b.out","w",stdout);
  79. #endif
  80. init(maxm-10);
  81. int T=read();
  82. while(T--){
  83. int L=read(),R=read();
  84. int t1=upper_bound(prime+1,prime+cnt+1,R/L)-prime;
  85. int t2;
  86. for(t2=0;prime[t2+1]*prime[t2+1]<=R;++t2);
  87. int t3=upper_bound(prime+1,prime+cnt+1,R)-prime-1;
  88. REP(i,L,R) Begin[i]=0;
  89. e=0;
  90. ans=(R-L+1);
  91. ans-=t1-1;
  92. if(R-L>=6000){
  93. REP(i,t1,t3) if(R/prime[i]>(L-1)/prime[i]) --ans;
  94. printf("%d\n",ksm(2,ans));
  95. continue;
  96. }
  97. // cerr<<t1<<' '<<t2<<' '<<t3<<endl;
  98. REP(i,t1,t2) REP(j,(L-1)/prime[i]+1,R/prime[i]){
  99. int u=j,x=1;
  100. while(u%prime[i]==0) u/=prime[i],x^=1;
  101. if(x) add_edge(prime[i]*j,i-t1);
  102. }
  103. tmp=(t2-t1)/64;
  104. tot=t2-t1;
  105. REP(i,0,tot){
  106. REP(j,0,tmp) bit[i][j]=0;
  107. p[i]=0;
  108. }
  109. All=tot;
  110. REP(i,max(t2+1,t1),t3){
  111. int l=(L-1)/prime[i]+1,r=R/prime[i];
  112. if(l>r) continue;
  113. ans--;
  114. if(All<0) continue;
  115. if(l==r) continue;
  116. REP(j,0,tmp) num[j]=0;
  117. for(int j=Begin[l*prime[i]];j;j=Next[j]) num[to[j]/64]^=(1ll<<(ll)(to[j]%64));
  118. REP(j,l+1,r){
  119. REP(k,0,tmp) a[k]=num[k];
  120. for(int k=Begin[j*prime[i]];k;k=Next[k]) a[to[k]/64]^=(1ll<<(ll)(to[k]%64));
  121. add();
  122. if(All<0) break;
  123. }
  124. }
  125. REP(i,L,R) if(Max[i]<=t2){
  126. if(All<0) break;
  127. REP(j,0,tmp) a[j]=0;
  128. for(int j=Begin[i];j;j=Next[j]) a[to[j]/64]^=(1ll<<(ll)(to[j]%64));
  129. add();
  130. }
  131. printf("%d\n",ksm(2,ans));
  132. }
  133. return 0;
  134. }

座位

题目描述

有 \(n\) 张圆桌排成一排(从左到右依次编号为 $ 0 $ 到 $ n−1 $ ),每张桌子有 $ m $ 个座位(按照逆时针依次编号为$ 0$ 到 \(m−1\) ),在吃饭时每个座位上都有一个人;在吃完饭后的时候,每个人都需要选择一个新的座位(新座位可能和原来的座位是同一个),具体来说,第 $ i $ 桌第 $ j $ 个人的新座位只能在第 $ L_{i,j} $ 桌到第 $ R_{i,j} $ 桌中选,可以是这些桌中的任何一个座位。确定好新座位之后,大家开始移动,移动的体力消耗按照如下规则计算:

移动座位过程分为两步:

  1. 从起始桌移动到目标桌对应座位,这个过程中的体力消耗为两桌距离的两倍,即从第 $ i $ 桌移动到第 $ j $ 桌对应座位的体力消耗为$ 2\times |i−j|$;

2.从目标桌的对应座位绕着桌子移动到目标座位,由于桌子是圆的,所以客人会选择最近的方向移动,体力消耗为移动距离的一倍,即从编号为 $ x $ 的座位移动的编号为 $ y$ 的座位的体力消耗为 $ min(|x−y|,m−|x−y|)$;

详情如下图:

现在,给定每个客人的限制(即每个人的新座位所在的区间),需要你设计一个方案,使得所有客人消耗的体力和最小本题中假设客人在移动的时候互不影响。

输入格式

从标准输入读入数据。

第一行输入两个数 $ n $和 $ m$ ;

接下来输入 $ n$ 行,每行 $ m $ 个空格隔开的整数描述矩阵 $ L$ :其中,第 $ i $ 行的第 $ j $ 个数表示 $ L_{i,j}$;

接下来输入 $ n$ 行,每行 $ m $ 个空格隔开的整数描述矩阵 $ R$ :其中,第 $ i $ 行的第 $ j $ 个数表示 $ R_{i,j}$。

数据是随机生成的

输出格式

输出到标准输出。

输出总体力消耗的最小值,如果没有合法的方案输出no solution

数据范围

$1≤n≤300 , 1≤m≤10 , 0≤L_{i,j}≤R_{i,j}≤n−1 $

题解

这道题应该是这一场里最简单的题,很容易想到费用流,每个桌子里的相邻两个座位连边,桌子之间的连边的话就线段树优化建边即可,注意对于向左和向右要开两个线段树。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define REP(i,st,ed) for(register int i=st,i##end=ed;i<=i##end;++i)
  4. #define DREP(i,st,ed) for(register int i=st,i##end=ed;i>=i##end;--i)
  5. typedef long long ll;
  6. template<typename T>inline bool chkmin(T &x,T y){return (y<x)?(x=y,1):0;}
  7. template<typename T>inline bool chkmax(T &x,T y){return (y>x)?(x=y,1):0;}
  8. inline int read(){
  9. int x;
  10. char c;
  11. int f=1;
  12. while((c=getchar())!='-' && (c>'9' || c<'0'));
  13. if(c=='-') f=-1,c=getchar();
  14. x=c^'0';
  15. while((c=getchar())>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0');
  16. return x*f;
  17. }
  18. inline ll readll(){
  19. ll x;
  20. char c;
  21. int f=1;
  22. while((c=getchar())!='-' && (c>'9' || c<'0'));
  23. if(c=='-') f=-1,c=getchar();
  24. x=c^'0';
  25. while((c=getchar())>='0' && c<='9') x=(x<<1ll)+(x<<3ll)+(c^'0');
  26. return x*f;
  27. }
  28. const int inf=0x3f3f3f3f,maxn=1e5+10,maxm=1e6+10;
  29. int ans,Flow,n,S,T;
  30. struct Min_cost_Max_Flow{
  31. int vis[maxn],cur[maxn],Begin[maxn],Next[maxm],to[maxm],w[maxm],e,d[maxn],v[maxm];
  32. inline void add_edge(int x,int y,int f,int z){
  33. to[++e]=y;
  34. Next[e]=Begin[x];
  35. Begin[x]=e;
  36. w[e]=f;
  37. v[e]=z;
  38. }
  39. inline void add(int x,int y,int f,int z){
  40. // cout<<x<<' '<<y<<' '<<f<<' '<<z<<endl;
  41. add_edge(x,y,f,z),add_edge(y,x,0,-z);
  42. }
  43. inline bool spfa(){
  44. deque<int> q;
  45. REP(i,1,n) d[i]=inf;
  46. d[T]=0;q.push_back(T);
  47. while(!q.empty()){
  48. int u=q.front();q.pop_front();
  49. for(int i=Begin[u];i;i=Next[i])
  50. if(w[i^1]>0 && chkmin(d[to[i]],d[u]+v[i^1]))
  51. if(!vis[to[i]]){
  52. vis[to[i]]=1;
  53. if(!q.empty() && d[q.front()]>d[to[i]]) q.push_front(to[i]);
  54. else q.push_back(to[i]);
  55. }
  56. vis[u]=0;
  57. }
  58. return d[S]<inf;
  59. }
  60. int dfs(int x,int Min){
  61. if(!Min || x==T) return Min;
  62. int num,flow=0;
  63. vis[x]=1;
  64. for(int &i=cur[x];i;i=Next[i])
  65. if(!vis[to[i]] && w[i]>0 && d[to[i]]+v[i]==d[x] && (num=dfs(to[i],min(Min,w[i])))){
  66. ans+=num*v[i];
  67. w[i]-=num,w[i^1]+=num;
  68. flow+=num,Min-=num;
  69. if(!Min) break;
  70. }
  71. vis[x]=0;
  72. return flow;
  73. }
  74. inline void work(){
  75. while(spfa()){
  76. REP(i,1,n) cur[i]=Begin[i];
  77. Flow+=dfs(S,inf);
  78. }
  79. }
  80. }MCMF;
  81. int num[1010][11],Nw;
  82. struct Segment_tree{
  83. int id[4010];
  84. void build_tree(int x,int L,int R,int ty){
  85. id[x]=++n;
  86. if(L==R){
  87. MCMF.add(n,num[L][Nw],inf,0);
  88. return;
  89. }
  90. int Mid=(L+R)>>1;
  91. build_tree(x<<1,L,Mid,ty),build_tree(x<<1|1,Mid+1,R,ty);
  92. if(ty) MCMF.add(id[x],id[x<<1],inf,2*(R-Mid)),MCMF.add(id[x],id[x<<1|1],inf,0);
  93. else MCMF.add(id[x],id[x<<1],inf,0),MCMF.add(id[x],id[x<<1|1],inf,2*(Mid-L+1));
  94. }
  95. void query(int x,int L,int R,int ql,int qr,int ty,int fr){
  96. if(ql<=L && R<=qr){
  97. if(ty) MCMF.add(fr,id[x],1,2*(Nw-R));
  98. else MCMF.add(fr,id[x],1,2*(L-Nw));
  99. return;
  100. }
  101. int Mid=(L+R)>>1;
  102. if(ql<=Mid) query(x<<1,L,Mid,ql,qr,ty,fr);
  103. if(qr>Mid) query(x<<1|1,Mid+1,R,ql,qr,ty,fr);
  104. }
  105. }Seg0[11],Seg1[11];
  106. int L[1010][11],R[1010][11];
  107. int main(){
  108. #ifndef ONLINE_JUDGE
  109. freopen("a.in","r",stdin);
  110. freopen("a.out","w",stdout);
  111. #endif
  112. int N=read(),M=read();
  113. S=++n,T=++n;
  114. MCMF.e=1;
  115. REP(i,1,N) REP(j,1,M) num[i][j]=++n,MCMF.add(n,T,1,0);
  116. REP(i,1,M) Nw=i,Seg0[i].build_tree(1,1,N,0),Seg1[i].build_tree(1,1,N,1);
  117. if(M>1) REP(i,1,N){
  118. REP(j,1,M-1) MCMF.add(num[i][j],num[i][j+1],inf,1),MCMF.add(num[i][j+1],num[i][j],inf,1);
  119. MCMF.add(num[i][1],num[i][M],inf,1),MCMF.add(num[i][M],num[i][1],inf,1);
  120. }
  121. REP(i,1,N) REP(j,1,M) L[i][j]=read()+1;
  122. REP(i,1,N) REP(j,1,M) R[i][j]=read()+1;
  123. REP(i,1,N) REP(j,1,M){
  124. ++n;
  125. MCMF.add(S,n,1,0);
  126. Nw=i;
  127. if(R[i][j]<=i) Seg1[j].query(1,1,N,L[i][j],R[i][j],1,n);
  128. else if(L[i][j]>=i) Seg0[j].query(1,1,N,L[i][j],R[i][j],0,n);
  129. else{
  130. Seg1[j].query(1,1,N,L[i][j],i,1,n);
  131. Seg0[j].query(1,1,N,i+1,R[i][j],0,n);
  132. }
  133. }
  134. MCMF.work();
  135. if(Flow!=N*M) printf("no solution\n");
  136. else printf("%d\n",ans);
  137. return 0;
  138. }

THUSC2017 Day1题解的更多相关文章

  1. 【NOIP2014】Day1题解+代码

    Day1 T1 签到题,模拟一下随便写就能过. 不过小心像我一样表打错傻逼的调了10min. #include <algorithm> #include <iostream> ...

  2. ZJOI2019 Day1 题解

    想要继续向前,就从克服内心的恐惧开始. 麻将 题意 在麻将中,我们称点数连续的三张牌或三张点数一样的成为面子,称两张点数一样的牌为对子.一副十四张麻将牌的胡牌条件是可以分成四个面子和一个对子或者分成七 ...

  3. Noip 2016 Day1 题解

    老师让我们刷历年真题, 然后漫不经心的说了一句:“你们就先做做noip2016 day1 吧” ...... 我还能说什么,,,,,老师你这是明摆着伤害我们啊2333333333 预计分数:100+2 ...

  4. NOI 2016 Day1 题解

    今天写了NOI2016Day1的题,来写一发题解. T2 网格 题目传送门 Description \(T\) 次询问,每次给出一个 \(n\times m\) 的传送门,上面有 \(c\) 个位置是 ...

  5. 十连测Day1 题解

    A. 奥义商店 有一个商店,n个物品,每个物品有一个价格和一种颜色. 有m个操作,操作有两种,一种是修改一个位置的价格,另一种是购买,每次购买指定一个公差d和一个位置k,找到包含这个位置k公差为d的同 ...

  6. 【NOIP2013】DAY1题解+代码

    T1 傻逼快速幂,敲敲就过了. 我跟你们讲个笑话当时我以为这个数据范围过不了于是想出了求GCD再推规律什么的magic方法中途还咨询了某个学长. 然后怎么想都是不可做. ……直到我发现我昨年的代码一个 ...

  7. NOIP 2018 day1 题解

    今年noip的题和去年绝对是比较坑的题了,但是打好的话就算是普通水准也能350分以上吧. t1: 很显然这是一个简单的dp即可. #include<iostream> #include&l ...

  8. 【2018暑假集训模拟一】Day1题解

    T1准确率 [题目描述] 你是一个骁勇善战.日刷百题的OIer. 今天你已经在你OJ 上提交了y 次,其中x次是正确的,这时,你的准确率是x/y.然而,你最喜欢一个在[0; 1] 中的有理数p/q(是 ...

  9. noi2017 day1 题解

    d1t1 sol1:用线段树维护区间是否全0/全1,叶子上压位维护对应位置的数位,加法首先对叶子加,如需进位则向右找到第一个不是全1的叶子+1,中间部分全1部分打上反转标记,减法同理. #includ ...

随机推荐

  1. Mysql 中的MVCC原理,undo日志的依赖

    一. MVCC 原理了解   原文点击:MVCC原理浅析 读锁: 也叫共享锁.S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的 ...

  2. NEST.net Client

    NEST.net Client For Elasticsearch简单应用 由于最近的一个项目中的搜索部分要用到 Elasticsearch 来实现搜索功能,苦于英文差及该方面的系统性资料不好找,在实 ...

  3. Vue父子传值

    昨天创建完项目以后,今日首先使用项目来做一个简单的导航栏体会一下Vue的使用 1.项目的结构: 2.首先在Vheader.Vue中编辑代码: <template> <header c ...

  4. Hibernate two table same id

    Hibernate更新数据(不用update也可以) - 森林木马 - 博客园 https://www.cnblogs.com/owenma/p/3481497.html hibernate级联更新会 ...

  5. npm --save-dev 和--save 参数的区别

    npm中的--save与--save-dev参数的区别 --save一般规定把产品运行时(或生产环境)需要的npm包存入到package.json的dependencies中: --save-dev则 ...

  6. WIndows下使用Grafana+InfluxDB打造监控系统

     前言 对于一个运维DBA来说,了解数据库的TPS.QPS很有必要(QPS:每秒查询数,即对数据库每秒的DML的操作数:TPS:每秒事物处理,即对数据库每秒DDL操作数),通过了解他们,可以掌握一个实 ...

  7. CSS自定义属性expression_r

    CSS的出现使网页制作者在对网页元素的控制方便许多,当然,有利必有弊,CSS只能对颜色.大小.距离等静态样式有效,对于要实现某些html元素的动态样式就显得有些力不从心.有了CSS的自定义属性expr ...

  8. 在windows 7 和linux上安装xlwt和xlrd

    在windows 7上安装xlwt xlrd xlwt是开源社区编写的python库,需要单独安装,下载地址https://pypi.python.org/pypi/xlwt 目前xlwt最新的版本是 ...

  9. 集合之TreeMap(含JDK1.8源码分析)

    一.前言 前面所说的hashMap和linkedHashMap都不具备统计的功能,或者说它们的统计性能的时间复杂度都不是很好,要想对两者进行统计,需要遍历所有的entry,时间复杂度比较高,此时,我们 ...

  10. JDBC 初始。

    package cn.zhouzhou; /* 一.JDBC? 1.(java date base connectivity,java)是一种用于执行SQL语句的java API . 2.jdbc本质 ...