2018-2019 ACM-ICPC, Asia East Continent Finals
在此附上吉老师的视频题解
Problem C:Heretical … Möbius
思路:根据莫比乌斯系数的性质:4,9,25,49,121,169的倍数的系数均为0。因为题目给出了200个系数,那么假设 x x x为第1个数在系数表中的位置,所以我们可以得到以下方程
{ x ≡ a 1 , ( m o d 4 ) x ≡ a 2 , ( m o d 9 ) x ≡ a 3 , ( m o d 25 ) x ≡ a 4 , ( m o d 49 ) x ≡ a 5 , ( m o d 121 ) x ≡ a 6 , ( m o d 169 ) \begin{cases} x\equiv a_1,(mod 4)\\ x\equiv a_2,(mod 9)\\ x\equiv a_3,(mod 25)\\ x\equiv a_4,(mod 49)\\ x\equiv a_5,(mod 121)\\ x\equiv a_6,(mod 169) \end{cases} ⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧x≡a1,(mod 4)x≡a2,(mod 9)x≡a3,(mod 25)x≡a4,(mod 49)x≡a5,(mod 121)x≡a6,(mod 169)
接下来就是找出所有的 a i a_i ai,然后暴力枚举 a i a_i ai,利用中国剩余定理来计算出 x x x并验证。
#include
using namespace std;
const int MAX=5e4+10;
const int INF=1e9+7;
const int LCM=901800900;
typedef long long ll;
vectorv[6];
vectorpr;
ll u[MAX];
ll g[6]={4,9,25,49,121,169};
ll num[210];
ll p[6];
ll ans=INF;
ll mu(ll x)
{
if(xx)break;
if(x%(pr[i]*pr[i])==0)return 0;
while(x%pr[i]==0)x/=pr[i];
}
return 1;
}
void exgcd(ll a,ll b,ll &gcd,ll &x,ll &y)
{
if(b==0){x=1,y=0;gcd=a;}
else{exgcd(b,a%b,gcd,y,x);y-=(a/b)*x;}
}
ll CRT(int n,ll *a,ll *m)
{
ll M=m[0],ANS=a[0],gcd,x,y;
for(int i=1;i1e9)break;
if(i>=ans)break;
int ok=1;
for(ll j=i;j<=i+199;j++)if(mu(j)!=num[j-i+1]){ok=0;break;}
if(ok){ans=min(ans,i);break;}
}
}
void dfs(int k)//暴力枚举ai
{
if(k==6){cal();return;}
for(int j=v[k].size()-1;j>=0;j--)//如果j改为从0开始连过样例都很艰难
{
p[k]=v[k][j];
dfs(k+1);
}
}
bool isp[MAX];
void init()
{
memset(isp,0,sizeof isp);
for(int i=1;i
Problem F:Interstellar … Fantasy
思路:将S,T,O投影到一个二维平面上计算,还要判断ST是否与圆O相交。
#include
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
struct Point{int x,y,z;}O,S,T;
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y,A.z-B.z};}
int operator*(Point A,Point B){return A.x*B.x+A.y*B.y+A.z*B.z;}
int operator==(Point A,Point B){return A.x==B.x&&A.y==B.y&&A.z==B.z;}
int dis2(Point A,Point B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z);}
double dis(Point A,Point B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));}
int main()
{
int cas;
cin>>cas;
while(cas--)
{
int R;
scanf("%d%d%d%d",&O.x,&O.y,&O.z,&R);
scanf("%d%d%d",&S.x,&S.y,&S.z);
scanf("%d%d%d",&T.x,&T.y,&T.z);
if(S==T){puts("0");continue;}//S T重合
double OST=acos((dis2(S,O)+dis2(S,T)-dis2(O,T))/(2*dis(O,S)*dis(S,T)));
double h=sin(OST)*dis(S,O); //圆心到ST的距离
if(h>=R||(O-S)*(T-S)<0||(O-T)*(S-T)<0){printf("%.10f\n",dis(S,T));continue;}//ST不与圆相交
double ang=acos((dis2(S,O)+dis2(T,O)-dis2(S,T))/(2*dis(S,O)*dis(T,O)));
double ans=sqrt(dis2(O,S)-R*R)+sqrt(dis2(O,T)-R*R);
ans+=(ang-acos(R/dis(O,S))-acos(R/dis(O,T)))*R;
printf("%.10f\n",ans);
}
return 0;
}
Problem I: Misunderstood … Missing
思路:倒着DP。 d [ i ] [ j ] [ k ] d[i][j][k] d[i][j][k]表示当前为第 i i i个回合,攻击了 j j j次,攻击回合的下标和为 k k k的最大伤害值。
#include
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll a[110],b[110],c[110];
ll d[2][101][5051];
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
memset(d,-1,sizeof d);
int pre=0,now=1;
for(int i=n;i>=1;i--)
{
if(i==n)d[now][1][n]=a[i];
else
{
for(int j=1;j<=n-i;j++)
for(int k=n;k<=(i+n)*(n-i+1)/2;k++)
{
if(d[pre][j][k]==-1)continue;
d[now][j+1][k+i]=max(d[now][j+1][k+i],d[pre][j][k]+a[i]);
d[now][j][k]=max(d[now][j][k],d[pre][j][k]+b[i]*(k-j*i));
d[now][j][k]=max(d[now][j][k],d[pre][j][k]+c[i]*j);
}
}
now^=1;
pre^=1;
memset(d[now],-1,sizeof d[now]);
}
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=n;j<=(1+n)*n/2;j++)ans=max(ans,d[pre][i][j]);
cout<
Problem L: Eventual … Journey
思路:我们可以将节点分为4种:与1无边相连的0点,这种点记为 A A A;与1相连的0点,记为 B B B;与0相连的1点,记为 C C C;与0不相连的1点,记为 D D D。
A与B之间的距离为1;
A与C之间的距离为2(当存在0点与1点相连的边时);
A与D之间的距离为3(当存在0点与1点相连的边时)。
任意两节点距离最大为3,我们记录一下每个点与互异的点的连边数,最后遍历一边讨论一下。
#include
using namespace std;
const int MAX=2e5+10;
const int MOD=1e9+7;
typedef long long ll;
int cnt[MAX];
int ans[MAX];
int a[MAX];
int main()
{
int n,m,zero=0,one=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==0)zero++;
else one++;
}
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
if(a[x]!=a[y])
{
cnt[x]++;
cnt[y]++;
}
}
int A=0,B=0;
for(int i=1;i<=n;i++)
{
if(a[i]==0&&cnt[i])A++;
if(a[i]==1&&cnt[i])B++;
}
for(int i=1;i<=n;i++)
{
ans[i]+=cnt[i];
if(a[i]==0)ans[i]+=zero-1;
else ans[i]+=one-1;
if(cnt[i]==0)
{
if(a[i]==0)
{
ans[i]+=2*B;
ans[i]+=3*(one-B);
}
else
{
ans[i]+=2*A;
ans[i]+=3*(zero-A);
}
}
else
{
if(a[i]==0)ans[i]+=2*(one-cnt[i]);
else ans[i]+=2*(zero-cnt[i]);
}
}
for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'\n':' ');
}