我好菜啊。。。。。
92只会打暴力,93暴力都不会了
模拟92,
T1:直接ex_gcd加分类讨论即可
T2:考场只会打暴搜,正解为排序后线段树解决,排序的关键字为a+b,因为如果ai
1 #include
2 #define N 100050
3 #define LL long long
4 using namespace std;
5 int n,pd[N],cnt,lsh[N<<1],ls;
6 long long dp[N],ans;
7 struct node{
8 int a,b,w;
9 friend bool operator <(const node &x,const node &y)
10 {
11 return x.a+x.by.b;
12 }
13 }q[N];
14 inline void init()
15 {
16 for(int i=1;i<=n;++i)lsh[++ls]=q[i].a,lsh[++ls]=q[i].b;
17 sort(lsh+1,lsh+ls+1);ls=unique(lsh+1,lsh+ls+1)-lsh-1;
18 for(int i=1;i<=n;++i){
19 q[i].a=lower_bound(lsh+1,lsh+ls+1,q[i].a)-lsh;
20 q[i].b=lower_bound(lsh+1,lsh+ls+1,q[i].b)-lsh;
21 }sort(q+1,q+n+1);
22 }
23 LL ma[N<<3],tag[N<<3];
24 inline void plu(int g,LL w){ma[g]+=w,tag[g]+=w;}
25 inline void upd(int g){ma[g]=max(ma[g<<1],ma[g<<1|1]);}
26 inline void down(int g){plu(g<<1,tag[g]),plu(g<<1|1,tag[g]);tag[g]=0;}
27 void add(int g,int l,int r,int x,int y,int w)
28 {
29 if(l>y||rreturn;if(l>=x&&r<=y)return plu(g,w);
30 if(tag[g])down(g);const int m=l+r>>1;
31 add(g<<1,l,m,x,y,w);add(g<<1|1,m+1,r,x,y,w);
32 upd(g);
33 }
34 void change(int g,int l,int r,int pos,LL w)
35 {
36 if(l==r)return (void)(ma[g]=max(ma[g],w));
37 if(tag[g])down(g);const int m=l+r>>1;
38 if(pos<=m)change(g<<1,l,m,pos,w);
39 else change(g<<1|1,m+1,r,pos,w);
40 upd(g);
41 }
42 LL ask(int g,int l,int r,int x,int y)
43 {
44 if(l>y||rreturn 0;
45 if(l>=x&&r<=y)return ma[g];
46 if(tag[g])down(g);
47 const int m=l+r>>1;
48 const LL a1=ask(g<<1,l,m,x,y),a2=ask(g<<1|1,m+1,r,x,y);
49 return max(a1,a2);
50 }
51 inline void duizhangkuaipao()
52 {
53 for(int i=1;i<=n;++i)
54 {
55 dp[i]=ask(1,1,ls,1,min(q[i].a,q[i].b))+q[i].w;
56 add(1,1,ls,q[i].a,q[i].b,q[i].w);
57 change(1,1,ls,q[i].a,dp[i]);
58 }
59 ans=ma[1];
60 }
61 int main()
62 {
63 scanf("%d",&n);
64 for(int i=1;i<=n;++i)
65 scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].w);
66 init();
67 duizhangkuaipao();
68 cout<endl;
69 }
View Code
T3:多源点最短路,对于每个点维护到这个点的最短距离和对应的特殊点是那个,在扫描每条边时更新答案即可
1 #include
2 #define N 200050
3 #define LL long long
4 using namespace std;
5 int n,m,p,a[N],pd[N],bl[N];
6 const LL inf=10000000000000000;
7 LL dis[N],ans[N];
8 int he[N],ne[N<<2],to[N<<2],w[N<<2],tot;
9 inline void work1()
10 {
11 for(int i=1,x,y,z;i<=m;++i){
12 scanf("%d%d%d",&x,&y,&z);
13 ans[x]=min(ans[x],(LL)z);
14 ans[y]=min(ans[y],(LL)z);
15 }
16 for(int i=1;i<=p;++i)printf("%lld ",ans[a[i]]);
17 }
18 inline void addedge(int x,int y,int z)
19 {
20 to[++tot]=y;ne[tot]=he[x];
21 w[tot]=z;he[x]=tot;
22 }
23 priority_queueint> >q;
24 #define mmp make_pair
25 #define fir first
26 #define sec second
27 inline void getans()
28 {
29 for(int i=0;i<=n;++i)dis[i]=inf;
30 for(int i=1;i<=p;++i)
31 dis[a[i]]=0,bl[a[i]]=a[i],q.push(mmp(0,a[i]));
32 LL d;int g;
33 while(q.size())
34 {
35 g=q.top().sec;
36 d=-q.top().fir;
37 q.pop();
38 if(dis[g]!=d)continue;
39 // printf("g:%d d:%lld\n",g,d);
40 for(int i=he[g];i;i=ne[i]){
41 if(bl[g]&&bl[to[i]]&&bl[to[i]]!=bl[g]){
42 // printf("g:%d to:%d blg:%d blt:%d new:%lld\n",g,to[i],bl[g],bl[to[i]],d+w[i]+dis[to[i]]);
43 ans[bl[g]]=min(ans[bl[g]],d+w[i]+dis[to[i]]);
44 ans[bl[to[i]]]=min(ans[bl[to[i]]],d+w[i]+dis[to[i]]);
45 }
46 if(dis[to[i]]>d+w[i]){
47 dis[to[i]]=d+w[i];bl[to[i]]=bl[g];
48 q.push(mmp(-dis[to[i]],to[i]));
49 }
50 }
51 }
52 }
53 inline void work2()
54 {
55
56
57 }
58 int main()
59 {
60 // freopen("distance.in","r",stdin);
61 // freopen("my.out","w",stdout);
62 scanf("%d%d%d",&n,&m,&p);
63 for(int i=1;i<=p;++i)scanf("%d",&a[i]),ans[a[i]]=inf,pd[a[i]]=1;
64 if(p==n){work1();return 0;}
65 for(int i=1,x,y,z;i<=m;++i)
66 {
67 scanf("%d%d%d",&x,&y,&z);
68 addedge(x,y,z);addedge(y,x,z);
69 }
70 getans();
71 for(int i=1;i<=p;++i)
72 printf("%lld ",ans[a[i]]);
73 }
View Code
模拟92,
T1:一眼二分,测大样例发现答案不连续,化一下式子发现是个三维偏序,打个cdq上去A掉。
正解为按a的前缀和排序,把b离散化,在树状数组中插入原数组下标,复杂度为nlogn
1 #include
2 #include
3 #include
4 #include
5 #define N 500050
6 #define LL long long
7 using namespace std;
8 int n,ans=1;
9 LL sb[N],lsh[N<<1];
10 int a[N],b[N],c[N],ls;
11 inline int read(){
12 int s=0,b=0;char c=getchar();
13 while(c>'9'||c<'0'){if(c=='-')b=1;c=getchar();}
14 while(c>='0'&&c<='9')s=s*10+c-'0',c=getchar();
15 if(b)return -s;
16 return s;
17 }
18 struct node{LL a;int b,id;}q[N],qq[N];
19 inline void init()
20 {
21 sort(lsh+1,lsh+ls+1);
22 ls=unique(lsh+1,lsh+ls+1)-lsh-1;
23 for(int i=0;i<=n;++i)
24 q[i].b=lower_bound(lsh+1,lsh+ls+1,sb[i])-lsh;
25 }
26 inline void add(int x,const int v){
27 while(x<=ls){
28 if(c[x]>v)c[x]=v;
29 x+=x&-x;
30 }
31 }
32 inline void del(int x){while(x<=ls){c[x]=n+10;x+=x&-x;}}
33 inline int ask(int x)
34 {
35 int ret=n+10;
36 while(x)
37 {
38 if(c[x]c[x];
39 x-=x&-x;
40 }
41 return ret;
42 }
43 inline void CDQ(int l,int r)
44 {
45 if(l==r)return;
46 const int m=l+r>>1;
47 CDQ(l,m);CDQ(m+1,r);
48 register int i=l,j=m+1,t,o=l;
49 while(j<=r)
50 {
51 while(i<=m&&q[j].a>=q[i].a){
52 add(q[i].b,q[i].id);
53 qq[o++]=q[i++];
54 }
55 t=q[j].id-ask(q[j].b);
56 if(t>ans)ans=t;
57 qq[o++]=q[j++];
58 }
59 for(int k=l;kk)del(q[k].b);
60 while(i<=m)qq[o++]=q[i++];
61 for(int i=l;i<=r;++i)q[i]=qq[i];
62 }
63 int main()
64 {
65 scanf("%d",&n);
66 lsh[++ls]=0;
67 for(int i=1,x;i<=n;++i)q[i].a=q[i-1].a+read(),q[i].id=i;
68 for(int i=1,x;i<=n;++i)lsh[++ls]=sb[i]=sb[i-1]+read(),c[i]=n+10;
69 c[0]=n+10;
70 init();
71 for(int i=n;i<=ls;++i)c[i]=n+10;
72 CDQ(0,n);
73 printf("%d\n",ans);
74 }
View Code
T2:暴力做法为区间dp,dp[i][j]表示区间[i,j]的答案,for枚举长度,for枚举区间左端点,for枚举根节点复杂度为O(n3)
利用决策单调性优化。发现在一个已有区间的右面插入一个点,原树的根不会左移。同理在右面插入,决策点不会右移。
dp的同时记录决策点即可
1 #include
2 #include
3 #include
4 #include
5 #define N 5050
6 #define LL long long
7 using namespace std;
8 int n,rt=1,po[N][N];
9 const LL inf=1ll<<50;
10 LL sum[N];
11 LL ans,dp[N][N];
12 int main()
13 {
14 scanf("%d",&n);
15 for(int i=1,x;i<=n;++i)scanf("%d",&x),sum[i]=sum[i-1]+x;
16 for(int i=1;i<=n;++i)dp[i][i]=sum[i]-sum[i-1],po[i][i]=i;
17 for(int len=2;len<=n;++len){
18 for(int i=1,j;i+len-1<=n;++i){
19 j=i+len-1;dp[i][j]=inf;
20 for(int k=po[i][j-1];k<=po[i+1][j];++k)
21 if(dp[i][k-1]+dp[k+1][j]<=dp[i][j]){dp[i][j]=dp[i][k-1]+dp[k+1][j],po[i][j]=k;}
22 dp[i][j]+=sum[j]-sum[i-1];
23 }
24 }
25 printf("%lld\n",dp[1][n]);
26 }
View Code
T3:高斯消元,期望题一般逆推。题解:
我们首先考虑单个的 k。设 fi 表示从 i 出发第一次到 k 的期望步数,那么
f k =0,f i =sigma(f j )/x i +1 (i!=k,j 为 i 的所有出边,x i 为 i 的出度),用高斯消元解出 f1 即可。
分治消元的具体做法是:先用前一半的方程进行消元,然后递归后一半;
(恢复原矩阵后)再用后一半的方程进行消元,然后递归前一半。这样当区间缩小到
单点时,这个方程并没有拿来消其它的方程,我们可以直接修改它并求出所有f i 。
类似思想可以参考我这篇题解:https://www.cnblogs.com/loadingkkk/p/11272338.html
1 #include
2 #include
3 #define N 320
4 #define LL long long
5 using namespace std;
6 const int mod=998244353;
7 int n,m,inv[500050];
8 LL a[N][N],c[11][N][N],b[N],dd[11][N],ans[N];
9 inline int qpow(int d,int z)
10 {
11 int ret=1;
12 for(;z;z>>=1,d=1ll*d*d%mod)
13 if(z&1)ret=1ll*ret*d%mod;
14 return ret;
15 }
16 inline void init(int n){for(int i=1;i<=n;++i)inv[i]=qpow(i,mod-2);}
17 int he[N],ne[500050],to[500050],d[N],tot;
18 inline void addedge(int x,int y)
19 {
20 to[++tot]=y;++d[x];
21 ne[tot]=he[x];he[x]=tot;
22 }
23 inline void Gauss(int l,int r,int x,int y)
24 {
25 for(int i=l;i<=r;++i)
26 {
27 const LL iv=qpow(a[i][i],mod-2);
28 for(int j=1;j<=n;++j)
29 {
30 if(j==i||!a[j][i])continue;
31 const LL pl=iv*a[j][i]%mod;
32 for(int o=x;o<=y;++o){
33 a[j][o]-=a[i][o]*pl%mod;
34 if(a[j][o]<0)a[j][o]+=mod;
35 }
36 b[j]-=b[i]*pl%mod;
37 if(b[j]<0)b[j]+=mod;
38 }
39 }
40 }
41 inline void solve(int dep,int l,int r)
42 {
43 if(l==r){ans[l]=b[1]*qpow(a[1][1],mod-2)%mod;return;}
44 for(int i=1;i<=n;dd[dep][i]=b[i],++i)
45 for(int j=1;j<=n;++j)
46 c[dep][i][j]=a[i][j];
47 const int m=l+r>>1;
48 Gauss(l,m,l,r);solve(dep+1,m+1,r);
49 for(int i=1;i<=n;b[i]=dd[dep][i],++i)
50 for(int j=1;j<=n;++j)
51 a[i][j]=c[dep][i][j];
52 Gauss(m+1,r,l,r);solve(dep+1,l,m);
53 }
54 inline void work()
55 {
56 for(register int i=1;i<=n;++i){
57 a[i][i]=b[i]=mod-1;
58 for(register int j=he[i];j;j=ne[j])
59 (a[i][to[j]]+=inv[d[i]])%=mod;
60 }
61 solve(1,1,n);
62 }
63 int main()
64 {
65 // freopen("walk.in","r",stdin);
66 scanf("%d%d",&n,&m);init(m);
67 for(int i=1,x,y;i<=m;++i){
68 scanf("%d%d",&x,&y);
69 addedge(x,y);
70 }
71 work();
72 for(int i=2;i<=n;++i)printf("%lld\n",ans[i]);
73 }
View Code
希望下一次能考好吧