7.6上午洛谷多校第二场

我依旧只切了1题

A题:

有两种攻击方式,第一种,造成a点伤害或不造成伤害;第二种,造成b点伤害或随机造成[0,b/2]中某一整数值的伤害。问是否有可能n次攻击打出正好m点伤害?

T<=10^6

n,m,a,b<=10^18

a<b

题解:

这题是比较繁杂的分情况讨论题。

情况可以分为两个大类,a>b/2和a<=b/2

a<=b/2的情况实际上能否打出m的伤害与a无关,暴力判断即可。

a>b/2的情况,能够使用的数是[0,b/2]、a、b,首先考虑用a去凑m,不足的将部分a补成b,如果还不行,则考虑用b去凑m,剩余部分用[0,b/2]来补足。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main()
 4 {
 5     //freopen("test.in","r",stdin);
 6     int t;
 7     scanf("%d",&t);
 8     while (t)
 9     {
10         t--;
11         long long n,m,a,b;
12         scanf("%lld%lld%lld%lld",&n,&m,&a,&b);
13         if (n==0)
14         {
15             if (m) printf("No\n");else printf("Yes\n");
16             continue;
17         }
18         if (b<m/n||(b==m/n&&m%n))
19         {
20             printf("No\n");
21             continue;
22         }
23         if (a>b/2)
24         {
25             long long py=min(n,m/a);
26             if (m-py*a==0)
27             {
28                 printf("Yes\n");
29                 continue;
30             }else
31             {
32                 py=m/b;
33                 n=n-py;
34                 m=m%b;
35                 if (m)
36                 {
37                     long long pp=min(m/a,n);
38                     m=m-pp*a;
39                     n=n-pp;
40                     if (!m)
41                     {
42                         printf("Yes\n");
43                         continue;
44                     }
45                     if (!n)
46                     {
47                         printf("No\n");
48                         continue;
49                     }
50                     if (n==1)
51                     {
52                         if (m<=b/2) printf("Yes\n");else printf("No\n");
53                         continue;
54                     }
55                     printf("Yes\n");
56                     continue;
57                 }
58                 printf("Yes\n");
59             }
60         }else
61         {
62             long long py=m/b;
63             n=n-py;
64             m=m%b;
65             if (m==0)
66             {
67                 printf("Yes\n");
68                 continue;
69             }
70             if ((n==2&&b/2+b/2>=m)||n>2)
71             {
72                 printf("Yes\n");
73                 continue;
74             }
75             if (m<=b/2)
76             {
77                 printf("Yes\n");
78                 continue;
79             }
80             printf("No\n");
81             continue;
82         }
83     }
84 }

 

H

n个点m条边的有向带权图,给定起点和终点,可以最多额外连接一条无向边,边权为两点编号差的平方,问起点到终点最短路

n<=2*10^5,m<=4*10^5,边权<=10^9

 

题解:

单源最短路求出起点到每个点的最短路,以及每个点到终点的最短路。

枚举无向边的其中一个端点u,设另一个端点为v,则答案为u*u+v*v-2uv+dis[s][u]+dis[v][t]

其中u*u和dis[s][u]为已知量,把v*v+dis[v][t]看作与v相关的函数,可以得到一个类似于凸包的东西,用斜率优化即可。

这题卡了spfa,所以要用dij

 

代码(spfa):

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e5+10;
 4 int ind[N],tot[2],ne[2][N*4],t[2][N*4],he[2][N],cc[2][N*4],p[N],q[N*30],p1[N],p2[N],n,sta[N];
 5 long long dis[2][N],c1[N],c2[N];
 6 void link(int w,int x,int y,int z)
 7 {
 8     tot[w]++;
 9     ne[w][tot[w]]=he[w][x];
10     he[w][x]=tot[w];
11     t[w][tot[w]]=y;
12     cc[w][tot[w]]=z;
13 }
14 void spfa(int w,int s)
15 {
16     for (int i=1;i<=n;i++) p[i]=0,dis[w][i]=-1;
17     int i=0,k=1;
18     q[1]=s;
19     dis[w][s]=0;
20     p[s]=1;
21     while (i<k)
22     {
23         i++;
24         if (i<k&&dis[w][q[i]]>dis[w][q[i+1]]) swap(q[i],q[i+1]);
25         int x=q[i];
26         for (int j=he[w][x];j;j=ne[w][j]) if (dis[w][t[w][j]]==-1||dis[w][t[w][j]]>dis[w][x]+cc[w][j])
27         {
28             dis[w][t[w][j]]=dis[w][x]+cc[w][j];
29             if (!p[t[w][j]])
30             {
31                 k++;
32                 q[k]=t[w][j];
33                 p[t[w][j]]=1;
34             }
35         }
36         p[x]=0;
37     }
38 }
39 long long V(int x,int y)
40 {
41     return 1ll*(x-y)*(x-y)+dis[0][x]+dis[1][y];
42 }
43 int main()
44 {
45     //freopen("test.in","r",stdin);
46     int m,s,t;
47     scanf("%d%d%d%d",&n,&m,&s,&t);
48     for (int i=1;i<=m;i++)
49     {
50         int x,y,z;
51         scanf("%d%d%d",&x,&y,&z);
52         link(0,x,y,z);
53         link(1,y,x,z);
54     }
55     spfa(0,s);
56     spfa(1,t);
57     long long ans=1ll*(s-t)*(s-t);
58     for (int i=1;i<=n;i++)
59     {
60         if (dis[0][i]==-1) dis[0][i]=2e14;
61         if (dis[1][i]==-1) dis[1][i]=2e14;
62         ans=min(ans,dis[0][i]+dis[1][i]);
63     }
64     sta[1]=1;
65     int he=1,ta=1;
66     ans=min(ans,V(1,1));
67     for (int i=2;i<=n;i++)
68     {
69         while (ta>he&&1ll*(V(1,sta[ta])-V(1,sta[ta-1]))*(i-sta[ta-1])>1ll*(V(1,i)-V(1,sta[ta-1]))*(sta[ta]-sta[ta-1])) ta--;
70         ta++;
71         sta[ta]=i;
72         ans=min(V(1,sta[ta]),ans);
73     }
74     for (int i=2;i<=n;i++)
75     {
76         while (he<ta&&V(i,sta[he])>=V(i,sta[he+1])) he++;
77         ans=min(ans,V(i,sta[he]));
78     }
79     printf("%lld\n",ans);
80 }

 

posted @ 2021-07-06 15:03  praying_cqf  阅读(28)  评论(0编辑  收藏  举报