20190729考试反思

  又是一场扔分的考试,T1暴力没调出来,T2没看到40分的点自己会,手扔40分。极限得分85+70+95=250然而实际25+30+95=150还是太菜了,现在才把T2改完。

  T1就是一个辣鸡。。。。额它就是个暴力,首先这道题没有思维含量。。但我还是很满意自己在考场上的挽救大脑短路的操作的,其实一开始我是没有发现矩形内部可以直接算,也就是说别人一下想到的东西我大脑间歇抽搐没想到,然鹅我通过一系列的分析从一些边缘信息得到了这个,首先坐标1e9就是刚会打for循环都知道这不能存矩阵,然后只能看输入什么存什么,那么它为什么是一个矩形一个矩形给,而且为什么这个第一个5分它只给一个矩形,然后通过想这5分怎么打的时候发现了矩形中间是可以直接算的,矩形之间$n^{2}$枚举算。然后就结束了,这是一个非常神奇的复杂度,没有啥正确证明,本人只能口胡一个:理论上来说卡它的极限数据是每个矩形周围都有n个矩形能形成氢键,然而yy一下发现这是不可能的,也就是说一个矩形只能和有限个矩形形成氢键,而这有限个又很小,就算一个矩形周围很多键,那一定是这个矩形很大旁边的很小,那些小的周围的键就会少很多,所以均摊下来很小。。。应该是这样吧

  

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int X=1e9;
 6 int rd()
 7 {
 8     int s=0,w=1;
 9     char cc=getchar();
10     while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
11     while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
12     return s*w;
13 }
14 struct mat{int xa,xb,ya,yb;}m[100020];
15 bool cmp1(mat a,mat b)
16 {
17     if(a.xa==b.xa) return a.ya<b.ya;    
18     return a.xa<b.xa;
19 }
20 signed main()
21 {
22     int n=rd();
23     if(n==1)
24     {
25         int xa=rd(),ya=rd(),xb=rd(),yb=rd();
26         printf("%lld\n",1ll*(xb-xa)*(yb-ya)*2);
27         return 0;
28     }
29     long long ans=0;
30     for(int i=1;i<=n;i++)
31     {
32         m[i].xa=rd(),m[i].ya=rd(),m[i].xb=rd(),m[i].yb=rd();
33         ans+=1ll*(m[i].xb-m[i].xa)*(m[i].yb-m[i].ya)*2;
34     }
35     sort(m+1,m+n+1,cmp1);
36     for(int i=1;i<=n;i++)
37     {
38         for(int j=i+1;j<=n;j++)
39         {
40             if(m[j].xa>m[i].xb+1)break;
41             else if(m[j].xa==m[i].xb+1)
42             {
43                 int a=m[i].ya,b=m[i].yb,c=m[j].ya,d=m[j].yb;
44                 int mu=min(a,c),mmu=max(a,c),md=max(b,d),mmd=min(b,d);
45                 if(mmu>mmd+1){continue;}
46                 else if(mmu==mmd+1){ans++;continue;}
47                 ans+=(md-mu)<<1;
48                 ans-=(mmu-mu)<<1;ans-=(md-mmd)<<1;
49                 if(mu!=mmu)ans++;
50                 if(md!=mmd)ans++;
51             }
52             else if(m[j].xa<=m[i].xb)
53             {
54                 if(m[j].ya!=m[i].yb+1&&m[i].ya!=m[j].yb+1) continue;
55                 int a=m[i].xa,b=m[i].xb,c=m[j].xa,d=m[j].xb;
56                 int mu=min(a,c),mmu=max(a,c),md=max(b,d),mmd=min(b,d);
57                 //if(mmu>mmd+1){continue;}
58                 //else if(mmu==mmd+1){ans++;continue;}
59                 ans+=(md-mu)*2;
60                 ans-=(mmu-mu)*2;ans-=(md-mmd)*2;
61                 if(mu!=mmu)ans++;
62                 if(md!=mmd)ans++;
63             }
64         }
65     }
66     printf("%lld\n",ans);
67 }
68 /*
69 g++ 1.cpp -o 1
70 ./1
71 10
72 1 8 8 9
73 0 3 10 7
74 0 0 7 0
75 0 2 9 2
76 4 10 8 10
77 10 0 10 2
78 0 10 0 10
79 8 0 9 1
80 0 8 0 9
81 9 8 10 8
82 */
View Code

 

  T2神仙题,这个题是之前一个题的加强版,每次对一个点到根路径上的所有点放一种颜色的球,每个点上放球的数量都有一个ki限制,首先辣鸡papa没看出来有8个k=1e5的点,这是说每个点没限制,然后手动扔分。。。。以后要好好看每个部分分。那么我们先说正解,这个题我一开始的思路就是,树上差分每点维护权值线段树。然而这没法进行限制,再仔细想一下的话我会发现对于一个权值线段树我是没有办法进行时间统计的,那么我就想到了用时间为下标,那这样就没法统计颜色个数,然后就在矛盾中迷失了自我。。。。。最后看到了题解,对于每个点,我维护一个线段树,计算每个球的贡献(如果之前出现过就是0,否则为1),和总球数,然后我就可以二分像求区间k大值一样求出球数为ki时的总贡献和。

  然后我就骂出了声,这**不是暴力么。。。听到Lrefrain神说启发式合并能保证这个复杂度是log,然后就快乐的AC了,于是学习了一下比较神奇的启发式合并,发现和树链剖分的复杂度保障及其相似。我们先看这道题暴力怎么打,比如说我要维护每个点的操作的一个vector,这个东西相当于一个差分完的vector,代表某个节点比子节点多那些操作,那么我们把子树的vector全部合并,这才是这个节点的所有操作,然后把这个vector塞进线段树,统计一下答案。时间耗在了子树vector的合并上,要是每次都清vector然后每次重新搜子树会T,所有vector保留下来会M。。。

  启发式合并就是让它其它儿子合并到重儿子上,重儿子不变,即:我每次dfs操作时,分情况,如果先搜当前的轻儿子,统计轻儿子答案,并清掉轻儿子用的线段树,然后递归重儿子,这次递归不清信息,一会再次递归所有轻儿子,把轻儿子的vector塞到x中,并更新当前节点线段树,之所以不能把两次轻儿子合并就是因为,如果合并那么要么把重儿子信息一起清了,要么一起留下,没法达到目的。这样我相当于保留一部分信息,临时处理一部分信息,让他既不M,也不T,就像好多数据结构干的事。我们通过重儿子划分让他保留的和临时处理达到一个最折中的方案。时间复杂度可以达到nlog,本人好像只会口胡证明,粘一发L神的题解

  

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdio>
  4 #include<vector>
  5 #include<map>
  6 #define int long long
  7 using namespace std;
  8 const int N=1000020,M=1000020;
  9 int k[N],fr[N*2],fa[N],rt[N],size[N],ans[N],check[N],son[N],tt,tot,cnt,n,m;
 10 struct node{int fr,to,pr,f;}mo[N*2];
 11 struct flag{int t,c;};
 12 struct tree{int l,r,f,w,c;}tr[N*4];
 13 map<int,int> p;
 14 vector<flag> v[N];
 15 int rd()
 16 {
 17     int s=0,w=1;
 18     char cc=getchar();
 19     while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
 20     while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
 21     return s*w;
 22 }
 23 void add(int x,int y)
 24 {
 25     mo[++tt].fr=x;
 26     mo[tt].to=y;
 27     mo[tt].pr=fr[x];
 28     fr[x]=tt;
 29 }
 30 inline void clear(int k)
 31 {
 32     tr[k].w=tr[k].c=0;
 33     tr[k].f=1;
 34 }
 35 void down(int k)
 36 {
 37     tr[k].f=0;
 38     clear(k<<1);clear(k<<1|1);
 39 }
 40 void build(int k,int l,int r)
 41 {
 42     tr[k].l=l,tr[k].r=r;
 43     if(l==r)
 44     {
 45         tr[k].w=0;
 46         return ;
 47     }
 48     int mid=l+r>>1;
 49     build(k<<1,l,mid);build(k<<1|1,mid+1,r);
 50     tr[k].w=tr[k<<1].w+tr[k<<1|1].w;
 51 }
 52 void cut(int k,int id)
 53 {
 54     int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
 55     if(l==r)
 56     {
 57         tr[k].c=0;
 58         return ;
 59     }
 60     if(tr[k].f) down(k);
 61     if(id<=mid) cut(k<<1,id);
 62     else cut(k<<1|1,id);
 63     tr[k].c=tr[k<<1].c+tr[k<<1|1].c;
 64 }
 65 void addw(int k,int id)
 66 {
 67     int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
 68     if(l==r)
 69     {
 70         tr[k].w++;
 71         return;
 72     }
 73     if(tr[k].f) down(k);
 74     if(id<=mid) addw(k<<1,id);
 75     else addw(k<<1|1,id);
 76     tr[k].w=tr[k<<1].w+tr[k<<1|1].w; 
 77 }
 78 void addc(int k,int id)
 79 {
 80     int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
 81     if(l==r)
 82     {
 83         tr[k].c=1;
 84         return ;
 85     }
 86     if(tr[k].f) down(k);
 87     if(id<=mid) addc(k<<1,id);
 88     else addc(k<<1|1,id);
 89     tr[k].c=tr[k<<1].c+tr[k<<1|1].c;
 90 }
 91 int find(int k,int w)
 92 {
 93     if(w<=0) return 0;
 94     int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
 95     if(l==r) return tr[k].c;
 96     if(tr[k].f) down(k);
 97     if(w<=tr[k<<1].w) return find(k<<1,w);
 98     else return tr[k<<1].c+find(k<<1|1,w-tr[k<<1].w);
 99 }
100 void dfs1(int x)
101 {
102     size[x]=1;
103     for(int i=fr[x];i;i=mo[i].pr)
104     {
105         int to=mo[i].to;
106         if(to==fa[x]) continue;
107         fa[to]=x;
108         dfs1(to);
109         size[x]+=size[to];
110         if(size[to]>size[son[x]]) son[x]=to;
111     }
112 }
113 void pushvector(int x,int to)
114 {
115     for(int i=0;i<v[to].size();i++)
116         v[x].push_back(v[to][i]);
117     v[to].clear();
118 }
119 void pushtree(int x)
120 {
121     for(int i=0;i<v[x].size();i++)
122     {
123         int t=v[x][i].t,c=v[x][i].c;
124         addw(1,t);
125         if(!check[c]) addc(1,t),check[c]=t;
126         else if(check[c]>t)
127         {
128             cut(1,check[c]);
129             addc(1,t);
130             check[c]=t;
131         }
132     }
133 }
134 void dfs2(int x,int op)
135 {
136     for(int i=fr[x];i;i=mo[i].pr)
137     {
138         int to=mo[i].to;
139         if(to==fa[x]||to==son[x]) continue;
140         dfs2(to,0);
141     }
142     if(son[x]) dfs2(son[x],1);
143     pushtree(x);
144     for(int i=fr[x];i;i=mo[i].pr)
145     {
146         int to=mo[i].to;
147         if(to!=fa[x]&&to!=son[x]) pushtree(to);
148     }
149     ans[x]=find(1,k[x]);
150     if(son[x])
151     {
152         pushvector(son[x],x);
153         swap(v[son[x]],v[x]);
154     }
155     for(int i=fr[x];i;i=mo[i].pr)
156     {
157         int to=mo[i].to;
158         if(to!=fa[x]&&to!=son[x])pushvector(x,to);
159     }
160     if(!op)
161     {
162         clear(1);
163         for(int i=0;i<v[x].size();i++) check[v[x][i].c]=0;
164     }
165 }
166 signed main()
167 {
168     n=rd();
169     for(int i=1,x,y;i<n;i++)
170     {
171         x=rd(),y=rd();
172         add(x,y),add(y,x);
173     }
174     for(int i=1;i<=n;i++)k[i]=rd();
175     dfs1(1);
176     //for(int i=1;i<=n;i++) cout<<son[i]<<endl;
177     m=rd();
178     build(1,1,m);
179     for(int i=1,x,y;i<=m;i++)
180     {
181         x=rd(),y=rd();
182         if(!p[y]) p[y]=++cnt;
183         v[x].push_back((flag){i,p[y]});
184     }
185     dfs2(1,0);
186     int q=rd();
187     for(int i=1,x,y;i<=q;i++)
188     {
189         x=rd();
190         printf("%lld\n",ans[x]);
191     }
192 }
193 /*
194 g++ -g 1.cpp -o 1
195 ./1
196 5
197 1 2
198 2 3
199 3 4
200 2 5
201 2 1 1 1 1
202 2
203 2 1
204 4 2
205 3
206 1
207 3
208 5
209 */
210 /*
211 g++ 1.cpp -o 1
212 ./1
213 10
214 3 10
215 2 5
216 3 2
217 2 6
218 1 9
219 8 7
220 7 4
221 3 8
222 3 1
223 15 47 23 22 9 16 45 39 21 13
224 10
225 10 7
226 9 3
227 5 1
228 5 2
229 9 4
230 10 9
231 2 4
232 10 1
233 2 6
234 7 9
235 3
236 1
237 2
238 3
239 */
View Code

 

 

 

  T3就很好办了,这就是一个简单的假期望,出题人好像出漏了,这个题正解复杂度$O(n^{2}m)$,但考完一看被DeepinC的mlog算法按在地上摩擦,手动打一下柿子应该是$ans=\frac{\sum\limits_{i=1}^{m}(i^k-(i-1)^k)*w[i]}{m^k}*(n-k+1)$,在下一看数据范围被误导了一下,然后写了个DP方程,表示连做k道题,最大值为j的方案数,柿子大概长这样:$f[i][j]=f[i-1][j]*(j-1)+\sum \limits_{k=1}^{j}f[i-1][k]$,然后这是$O(n^{3})$的,稍加优化干成$O(n^{2})$,也能把正解吊着打。。想去找一下出题人嘲讽一下。。而且出题人数据自己打自己脸是什么鬼。。为什么数据范围k<=n然后有一个k>n的点,导致全场几乎都少了5分。。。。

  

#include<cstdio>
#define p 1000000007
#define L long long
L n,m,k,l,t,w,d;
L pw(L b,L t,L a=1){for(;t;t/=2,b=b*b%p)if(t&1)a=a*b%p;return a;}
int main(){
    scanf("%lld%lld%lld",&n,&m,&k);if(k>n){puts("0");return 0;}
    for(int i=1;i<=m;++i)scanf("%lld",&w),t=pw(i,k),(d+=(t-l+p)%p*w)%=p,l=t;
    printf("%lld\n",d*(n-k+1)%p*pw(pw(m,k),p-2)%p);
}
DeepinC超长代码

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int mod=1e9+7;
int f[600][600],dp[600][600],w[600];
int rd()
{
    int s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
int qpow(int a,int k)
{
    int ans=1;
    for(;k;k>>=1,a=a*a%mod) if(k&1) ans=ans*a%mod;
    return ans;
}
signed main()
{
    int n=rd(),m=rd(),k=rd();
    if(k>n) 
    {
        puts("0");
        return 0;
    }
    for(int i=1;i<=m;i++) w[i]=rd();
    for(int i=1;i<=m;i++) f[1][i]=1;
    for(int t=2;t<=k;t++)
    {
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<i;j++)
                f[t][i]=(f[t][i]+f[t-1][j])%mod;
            f[t][i]=(f[t][i]+f[t-1][i]*i)%mod;
        }
    }
    int inv=qpow(m,k);
    inv=qpow(inv,mod-2);
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        ans=(ans+f[k][i]*w[i])%mod;
    }
    ans=ans*inv%mod;
    ans=ans*(n-k+1)%mod;
    printf("%lld\n",ans);
}
/*
g++ 3.cpp -o 3
./3
5 4 3
2 1 3 5
*/
本人DP

 

转载于:https://www.cnblogs.com/starsing/p/11269127.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值