【纪中受难记】——Day23:受刑

一个上午都在思考人生(实际上是为不会写而发愁),想着不会写倒是没关系,下午改就可以了。

然后就很煎熬。

没交所以没有成绩。


 

 

2908. 矩阵乘法(mat) (Standard IO)

Time Limits: 2000 ms  Memory Limits: 262144 KB  Detailed Limits   Goto ProblemSet

 

Description

给你一个 N*N 的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第 K 小数。

 

 

Input

第一行两个数 N,Q ,表示矩阵大小和询问组数;
接下来 N 行 N 列一共 N*N 个数,表示这个矩阵;
再接下来 Q 行每行 5 个数描述一个询问: x1,y1,x2,y2,k 表示找到以 (x1,y1) 为左上角、以 (x2,y2) 为右下角的子矩形中的第 K 小数。

 

Output

对于每组询问输出第 K 小的数。


 

 

Sample Input

2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3

Sample Output

1
3
 

Data Constraint

 
 

Hint

矩阵中数字是 10 ^ 9 以内的非负整数;
20% 的数据: N<=100,Q<=1000 ;
40% 的数据: N<=300,Q<=10000 ;
60% 的数据: N<=400,Q<=30000 ;
100% 的数据: N<=500,Q<=60000 。

 

 

这道题,文不对题(kusa)。

  方法是 整体二分+二维树状数组。

  没写过整体二分,大致讲一下:

 

整体二分类似于一些决策单调性分治,可以用来解决诸多区间第k小/大问题。

 

  solve(l,r,L,R)表示答案在[l,r]中,操作与[L,R] 有关。

  就是对询问区间和值域二分,然后分别讨论对答案的贡献,也是用树状数组求前缀和来解决。

  搞不过洛谷的究极卡常,最后吸氧气快了1s多

  具体看代码吧。

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int inf=1e9;
  4 const int N=510;
  5 const int N2=250010;
  6 const int Q=6e4+10;
  7 int n,qq,cnt;
  8 int ma[N][N],ans[Q];
  9 struct node{
 10     int x1,y1,x2,y2,k,id;
 11 }q[Q+N2],q1[Q+N2],q2[Q+N2];
 12     int a[N][N];
 13     inline int lb(int x){return x&(-x);}
 14     inline void add(int x,int y,int z){
 15         for(register int i=x;i<=n;i+=lb(i)){
 16             for(register int j=y;j<=n;j+=lb(j)){
 17                 a[i][j]+=z;
 18             }
 19         }
 20     }
 21     inline int query(int x,int y){
 22         if(!x||!y) return 0;
 23         int ans=0;
 24         for(register int i=x;i;i-=lb(i)){
 25             for(register int j=y;j;j-=lb(j)){
 26                 ans+=a[i][j];
 27             }
 28         }
 29         return ans;
 30     }
 31     inline int get_sum(int x1,int y1,int x2,int y2){
 32         return query(x2,y2)+query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1);
 33     }
 34 void solve(int l,int r,int L,int R){
 35     if(L>R) return;
 36     if(l==r){
 37         for(register int i=L;i<=R;i++){
 38             if(q[i].id){
 39                 ans[q[i].id]=l;
 40             }
 41         }
 42         return;
 43     }
 44     int mid=(l+r)>>1,cnt1=0,cnt2=0;
 45     for(register int i=L;i<=R;i++){
 46         if(q[i].id==0){//change
 47             if(q[i].k<=mid){
 48                 add(q[i].x1,q[i].y1,1);//如果在答案区间左边,会对后面做出1点贡献
 49                 q1[++cnt1]=q[i]; 
 50             }
 51             else{
 52                 q2[++cnt2]=q[i];
 53             }
 54         }
 55         else{//query
 56             int tmp=get_sum(q[i].x1,q[i].y1,q[i].x2,q[i].y2);
 57             if(tmp>=q[i].k){
 58                 q1[++cnt1]=q[i];
 59             }
 60             else{
 61                 q[i].k-=tmp;//在另一个区间查区间第k-tmp小 
 62                 q2[++cnt2]=q[i];
 63             }
 64         }
 65     }
 66     for(register int i=1;i<=cnt1;i++){
 67         if(!q1[i].id){
 68             add(q1[i].x1,q1[i].y1,-1);
 69         }
 70     }
 71     for(register int i=L;i<=L+cnt1-1;i++){
 72         q[i]=q1[i-L+1];
 73     }
 74     for(register int i=L+cnt1;i<=R;i++){
 75         q[i]=q2[i-L-cnt1+1];
 76     }
 77     solve(l,mid,L,L+cnt1-1);
 78     solve(mid+1,r,L+cnt1,R);
 79 }
 80 int read(){
 81     int x=0,f=1;
 82     char c=getchar();
 83     while(!isdigit(c)){
 84         if(c=='-') f=-1;
 85         c=getchar();
 86     }
 87     while(isdigit(c)){
 88         x=x*10+c-'0';
 89         c=getchar();
 90     }
 91     return x*f;
 92 }
 93 int main(){
 94     n=read(),qq=read();
 95     for(register int i=1;i<=n;i++){
 96         for(register int j=1;j<=n;j++){
 97             ma[i][j]=read();
 98             q[++cnt]=(node){i,j,0,0,ma[i][j],0};
 99         }
100     }
101     for(register int i=1;i<=qq;i++){
102         cnt++;
103         q[cnt].x1=read(),q[cnt].y1=read(),q[cnt].x2=read(),q[cnt].y2=read(),q[cnt].k=read();
104         q[cnt].id=i;
105     }
106     solve(0,inf,1,cnt);
107     for(register int i=1;i<=qq;i++){
108         printf("%d\n",ans[i]);
109     }
110     return 0;
111 }

 


3410. 【GDOI2014模拟】Tree (Standard IO)

Time Limits: 2000 ms  Memory Limits: 262144 KB  Detailed Limits  

Description

Wayne 在玩儿一个很有趣的游戏。在游戏中,Wayne 建造了N 个城市,现在他想在这些城市间修一些公路,当然并不是任意两个城市间都能修,为了道路系统的美观,一共只有M 对城市间能修公路,即有若干三元组(Ui, Vi,Ci) 表示Ui 和Vi 间有一条长度为Ci 的双向道路。当然,游戏保证了,若所有道路都修建,那么任意两城市可以互相到达。

Wayne 拥有恰好N - 1 支修建队,每支队伍能且仅能修一条道路。当然,修建长度越大,修建的劳累度也越高,游戏设定是修建长度为C 的公路就会有C 的劳累度。当所有的队伍完工后,整个城市群必须连通,而这些修建队伍们会看看其他队伍的劳累情况,若劳累情况差异过大,可能就会引发骚动,不利于社会和谐发展。Wayne 对这个问题非常头疼,于是他想知道,这N - 1 支队伍劳累度的标准差最小能有多少。

【纪中受难记】——Day23:受刑
 

Input

第一行两个正整数N 和M。

接下来M 行,每行三个正整数Ui,Vi,Ci。

Output

输出仅一行表示最小的标准差,保留4 位小数。
 

Sample Input

3 3
1 2 1
2 3 2
3 1 3

Sample Output

0.5000
 

Data Constraint

对于20% 的数据,M <= 20。

对于另外30% 的数据,Ci <= 10。

对于100% 的数据,N <= 100,M <= 2000,Ci <= 100。

  看到这题以为是LCT,实际上没有那么难。

  这道题的思想很巧妙,以0.25为一个单位来确定一个伪平均数,让所有边权值减去这个值并平方,以此建最小生成树,这样可以近似的减小差值,使当前答案贴近最终答案,再根据确定好的最小生成树重新算出真正的平均值,更新答案即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m;
 4 double minans=1e9;
 5 double maxc=0;
 6 const int N=2e3+10;
 7 struct edge{
 8     int x,y,id;
 9     double w;
10 }a[N],b[N];
11 int f[N];
12 bool cmp(edge t1,edge t2){
13     return t1.w<t2.w;
14 }
15 int findf(int x){
16     return f[x]==x?x:f[x]=findf(f[x]);
17 }
18 queue<double> k;
19 int main(){
20     scanf("%d%d",&n,&m);
21     for(int i=1;i<=m;i++){
22         cin>>a[i].x>>a[i].y>>a[i].w;
23         a[i].id=i;
24         maxc=max(maxc,a[i].w);
25     }
26     for(double i=0;i<=maxc;i+=0.25){
27         double ans=0;
28         double num=0;
29         for(int j=1;j<=n;j++) f[j]=j;
30         for(int j=1;j<=m;j++){
31             b[j]=a[j];
32             b[j].w=(a[j].w-i)*(a[j].w-i);
33         }
34         sort(b+1,b+m+1,cmp);
35         for(int j=1;j<=m;j++){
36             if(findf(b[j].x)!=findf(b[j].y)){
37                 num+=a[b[j].id].w;
38                 k.push(a[b[j].id].w);
39                 f[findf(b[j].x)]=findf(b[j].y);
40             }
41         }
42         num/=(n-1);
43         while(!k.empty()){
44             ans+=(k.front()-num)*(k.front()-num);
45             k.pop();
46         }
47         minans=min(minans,sqrt((double)ans/(n-1)));
48     }
49     printf("%.4f",minans);
50     return 0;
51 }

Points and Segments (Standard IO)

Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits    Special Judge Time Remaining: 00:00:00

Description

Lahub 在几何问题上准备得不充分,但是他听说这一年的IOI 选拔夏令营中会出现许多几何问题。深陷恐惧的Lahub 把他自己锁在了地下室里,并且开始思考这一类别的新题目。其中一个如下。
Lahub 想要在OX 轴上画n 条不同的线段[li,ri]。线段可以是红色和蓝色其中任意一种。图画是“好”的当且仅当满足接下来的条件:
    对于每个OX 轴上的点x,考虑所有包含点x 的线段,设有rx 个红线段和bx 个蓝线段包含点x,必须满足不等式|rx-bx|<=1。
线段[l,r] 包含点x 当且仅当l<= x<= r。
Lahub 给你所有线段的左右端点,你不得不找到一个“好”的画法给他。
 

Input

第一行包含整数n(1<= n <= 10^5)表示线段的数目。
接下来n 行中,第i 行包含两个整数li 和ri(0 <= li <= ri <= 10^9)表示第i 条线段的端点。保证所有线段不相同。

Output

如果给出的输入没有一个“好”的画法,输出单独一个整数-1。否则输出n 个整数;每个整数须为0 或1。第i 个整数表示第i 条线段的颜色(0 是红色,1 是
蓝色)。如果有多解,可以输出任意一种。
 

Sample Input

输入1:
2
0 2
2 3
输入2:
6
1 5
1 3
3 5
2 10
11 11
12 12

Sample Output

输出1:
0 1
输出2:
0 1 0 1 0 0
 

Data Constraint

对于20% 的数据,n <=10;
对于40% 的数据,n <=1000。

第一眼以为是网络流或者差分约束之类的,结果居然是欧拉回路……

表示并没有学过,开始学一学。

引用内容来源于OIWIKI

 

定义

 

通过图中所有边一次且仅一次行遍所有顶点的通路称为欧拉通路。

 

通过图中所有边一次且仅一次行遍所有顶点的回路称为欧拉回路。

 

具有欧拉回路的图称为欧拉图。

 

具有欧拉通路的图称为半欧拉图。

 

有向图的时候可以类似地定义。

 

性质

 

欧拉图中所有顶点的度数都是偶数。

 

若G是欧拉图,则它若干个边不重的圈的并。

 

判别法

 

G是欧拉图当且仅当G是连通的且没有奇度定点。

 

G是半欧拉图当且仅当G中恰有两个奇度定点。

 

对于这道题,我们将数据离散化,由线段端点从小到大连接无向边,最后将所有奇点(度数为奇数的点)从小到大排序,一共有偶数个,由1到2,3到4连边,最后跑一遍欧拉回路就能得到一组可行解。这个做法可以证明一定是正确的:

  我们将欧拉图上的点放到坐标轴上,因为欧拉图的每一个点度数均为偶数,因此:

1.对于一个点,以它为端点的边一定有偶数条(两条以它为端点的线段可以看做一条跨过它的边,虽然要计算两次),跨过它的边一定有偶数条,否则无法构成欧拉回路。

2.对于任意一个奇点,增加连边后不会让它超出答案范围(感性理解下)

以上两点都是瞎说的,yy一下即可。

不写了。


 

总结:明天要不要听计算几何呢?感觉很有意思,但是又想打比赛。

上一篇:leetcode每日刷题计划-简单篇day23


下一篇:C++ Primer Plus的若干收获--(七)