2016ACM/ICPC亚洲区大连站-补题
5971-Wrestling Match
题目隐藏条件:除去已经知道的好人和坏人,如果剩余的人恰好被分成两组,即便不知道这两组哪组是好人,也是输出YES
做法:dfs染色,如果没有起点,需要随意取一个起点并随机赋予颜色(这个起点只能取一个)
代码:
const int maxn=2e3+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
int n,m,x,y,u,v,col[maxn],flag;
vector<int> G[maxn];
void dfs(int x)
{
repp(i,0,G[x].size())
{
int v=G[x][i];
if (col[v]!=-1)
{
if (col[v]!=1-col[x])flag=0;
}
else
{
col[v]=1-col[x];
dfs(v);
}
}
}
int main()
{
while(~scanf("%d%d%d%d",&n,&m,&x,&y))
{
flag=1;
rep(i,1,n)col[i]=-1,G[i].clear();
rep(i,1,m)
{
scanf("%d%d",&u,&v);
G[u].pb(v);
G[v].pb(u);
}
rep(i,1,x)scanf("%d",&u),col[u]=1;
rep(i,1,y)scanf("%d",&u),col[u]=0;
rep(i,1,n)if (col[i]!=-1)dfs(i);
rep(i,1,n)
{
if (col[i]==-1)
{
col[i]=0;
dfs(i);
break;
}
}
rep(i,1,n)if (col[i]==-1)flag=0;
if (flag)printf("YES\n");
else printf("NO\n");
}
return 0;
}
5974-A Simple Math Problem
做法:
假设
x
=
p
1
a
1
p
2
a
2
.
.
.
p
n
a
n
x=p_1^{a_1}p_2^{a_2}...p_n^{a_n}
x=p1a1p2a2...pnan
y
=
p
2
b
2
p
3
b
3
.
.
.
p
m
b
m
y=p_2^{b_2}p_3^{b_3}...p_m^{b_m}
y=p2b2p3b3...pmbm
则
g
c
d
(
x
,
y
)
=
p
2
m
i
n
(
a
2
,
b
2
)
gcd(x,y)=p_2^{min(a_2,b_2)}
gcd(x,y)=p2min(a2,b2)
x
+
y
=
a
x+y=a
x+y=a
x
y
g
c
d
(
x
,
y
)
=
b
{xy\over gcd(x,y)}=b
gcd(x,y)xy=b
对于
a
a
a:
m
i
n
(
a
2
,
b
2
)
≤
p
2
min(a_2,b_2)\leq p_2
min(a2,b2)≤p2的次方
对于
b
b
b:
m
i
n
(
a
2
,
b
2
)
=
p
2
min(a_2,b_2)= p_2
min(a2,b2)=p2的次方
故
g
c
d
(
a
,
b
)
=
g
c
d
(
x
,
y
)
=
p
2
m
i
n
(
a
2
,
b
2
)
gcd(a,b)=gcd(x,y)=p_2^{min(a_2,b_2)}
gcd(a,b)=gcd(x,y)=p2min(a2,b2)
解一个一元二次方程即可
PS:这题目比较SB,输出答案必须小的在前大的在后
代码:
const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
ll a,b,g,dt,x,x1,x2,y1,y2;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
int main()
{
while(~scanf("%lld%lld",&a,&b))
{
g=gcd(a,b);
dt=a*a-4*b*g;
x=sqrt(dt);
if (dt<0||x*x!=dt)
{
printf("No Solution\n");
continue;
}
x1=(a+x)/2;x2=(a-x)/2;
y1=a-x1;y2=a-x2;
if (x1*y1==b*g&&(a+x)%2==0)printf("%lld %lld\n",min(x1,y1),max(x1,y1));
else if (x2*y2==b*g&&(a-x)%2==0)printf("%lld %lld\n",min(x2,y2),max(x2,y2));
else printf("No Solution\n");
}
return 0;
}
5976-Detachment
做法:
1.瞎列几组数据,发现尽可能的把数字拆的越多越好(除了拆成1之外)
2.拆出来的越平均越好
那么假设拆成2,3,4,…n的序列
根据平均的思想,将多余的数字均分给较大的数,从右往左分(贪心)
用乘法前缀和二分即可
证明不会,借鉴别人的博客
https://blog.csdn.net/qq_34374664/article/details/53466435
代码:
const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
const ll mod=1e9+7;
ll t,x,sum[maxn],mul[maxn],ans;
ll qpow(ll a,ll b){ll res=1;while(b){if (b&1)res=res*a%mod;a=a*a%mod;b>>=1;}return res;}
ll pre(ll l,ll r){return mul[r-1]*qpow(mul[l-2],mod-2)%mod;}
int main()
{
sum[0]=0;
mul[0]=1;
for (int i=1;i<=100000;i++)
{
sum[i]=sum[i-1]+(i+1);
mul[i]=mul[i-1]*(i+1)%mod;
}
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&x);
if (x<=4)
{
WW(x);
continue;
}
ll pos=upper_bound(sum+1,sum+1+100000,x)-sum-1;
ll res=x-sum[pos];
if (res==pos+1)ans=pre(3,pos+1)*(pos+3)%mod;
else ans=pre(2,pos-res+1)*pre(pos-res+3,pos+2)%mod;
WW(ans);
}
return 0;
}
5978-To begin or not to begin
做法:假设一共有
i
i
i个球(一个为红球)
d
p
1
[
i
]
dp1[i]
dp1[i]表示先手赢的概率,
d
p
2
[
i
]
dp2[i]
dp2[i]表示后手赢的概率
那么可以得到以下关系式:
d
p
1
[
i
]
+
d
p
2
[
i
]
=
1
dp1[i]+dp2[i]=1
dp1[i]+dp2[i]=1
d
p
2
[
i
]
=
1
i
∗
0
+
i
−
1
i
d
p
1
[
i
−
1
]
dp2[i]= {1\over i}*0+{i-1\over i}dp1[i-1]
dp2[i]=i1∗0+ii−1dp1[i−1]
d
p
1
[
1
]
=
1
dp1[1]=1
dp1[1]=1,
d
p
2
[
1
]
=
0
dp2[1]=0
dp2[1]=0
递推式和第一项有了 直接O(k)解
代码:
const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
const double eps=1e-7;
int k;
double dp1[maxn],dp2[maxn];
int main()
{
dp1[1]=1.0;
dp2[1]=0.0;
for (double i=2;100000-i>eps;i+=1.0)
{
dp2[int(i)]=(i-1)/i*(dp1[int(i)-1]);
dp1[int(i)]=1-dp2[int(i)];
}
while(~scanf("%d",&k))
{
if (fabs(dp1[k+1]-dp2[k+1])<eps)W(0);
else if (dp1[k+1]>dp2[k+1])W(1);
else W(2);
}
return 0;
}
5979-Convex
SB题
三角函数算面积
5980-Find Small A
SB题