Educational Codeforces Round 125 (Rated for Div. 2)
A - Integer Moves
- 签到
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=1e5+5;
void solve()
{
int x,y;
cin>>x>>y;
int d=sqrt(x*x+y*y);
if(x==0 && y==0) { cout<<0<<"\n"; }
else if(sqrt(x*x+y*y)-d<=0.0000001)
{
cout<<"1\n";
}
else cout<<"2\n";
}
signed main()
{
int T=1;
cin>>T;
while(T--) solve();
}
B - XY Sequence
- 签到
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=1e5+5;
void solve()
{
int n,b,x,y;
cin>>n>>b>>x>>y;
int s=0,ans=0;
for(int i=1;i<=n;i++)
{
if(s+x>b) s-=y;
else s+=x;
ans+=s;
}
cout<<ans<<"\n";
}
signed main()
{
int T=1;
cin>>T;
while(T--) solve();
}
C - Bracket Sequence Deletion
分析:
-
阅读理解题
分两类:
- 左端是’(’:直接跳
- 左端是’)’:跳到下一个’)’
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=1e5+5;
void solve()
{
int n;
string s;
cin>>n>>s;
s=' '+s;
int l=1,r=2, cnt=0;
while(r<=n)
{
if(s[l]=='(' || s[r]==s[l])
{
cnt++;
l=r+1; r=l;
}
r++;
}
cout<<cnt<<' '<<n-l+1<<"\n";
}
signed main()
{
int T=1;
cin>>T;
while(T--) solve();
}
D - For Gamers. By Gamers.
分析:
-
阅读理解+打表+二分答案(神仙打表)
-
令我方的伤害和血量分别为 ( a , b ) (a,b) (a,b),敌方为 ( c , d ) (c,d) (c,d), 我方的数量为n
则,我方能打死敌方的条件是:
d n a < b c n a b > c d \frac{d}{na}<\frac{b}{c} \\ nab>cd nad<cbnab>cd -
b [ i ] b[i] b[i] 表示花费i最大的伤害值(转换之后的),打个表即可
-
注意:调和级数的复杂度 O ( n × l n ( n ) ) O(n\times ln(n)) O(n×ln(n))
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=1e6+5;
int f[N],b[N];
void solve()
{
int n,c;
cin>>n>>c;
for(int i=1;i<=n;i++)
{
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
f[x]=max(f[x],y*z);
}
for(int i=1;i<=c;i++)
{
if(f[i])
{
for(int j=1;j*i<=c;j++)
{
b[i*j]=max(b[i*j],f[i]*j);
}
}
}
for(int i=1;i<=c;i++) b[i]=max(b[i],b[i-1]);
int m; cin>>m;
while(m--)
{
int x,y;
scanf("%lld%lld",&x,&y);
x*=y;
int l=1, r=c, ans=0;
while(l<=r)
{
int mid=l+r>>1;
if(b[mid]>x) r=mid-1, ans=mid;
else l=mid+1;
}
if(ans) cout<<ans<<"\n";
else cout<<"-1\n";
}
}
signed main()
{
int T=1;
//cin>>T;
while(T--) solve();
}
E - Star MST
分析:
-
组合数学 + DP
-
只需要给出根节点出发的n-1条边的长度,剩下的边的长度,就是由这些边推出来的
具体原理详见大佬
-
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前i条边,最大边到j时的方案(总数)
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=255, mo=998244353;
int ksm(int a,int b,int p=mo,int res=1)
{
for( ; b ; a=a*a%p, b>>=1) if(b&1) res=res*a%p;
return res;
}
int fac[N],inv[N];
void init(int n=N-2)
{
inv[0]=fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mo;
inv[n]=ksm(fac[n],mo-2);
for(int i=n-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%mo;
}
int C(int n,int m)
{
return fac[n]*inv[m]%mo*inv[n-m]%mo;
}
int dp[N][N];
void solve()
{
init();
int n,k;
cin>>n>>k;
dp[0][0]=1;
for(int i=0;i<n;i++)
{
for(int j=1;j<=k;j++)
{
for(int t=0;t+i<n;t++)
{
(dp[i+t][j]+=dp[i][j-1]*C(n-1-i,t)%mo*ksm(k-j+1,t*i+t*(t-1)/2))%=mo;
//这一状态表示将要选取t个j,对于这t个j有n-1-i个位置能占
//t*i:每添加1条边会跟之前的i个便分别连线
//t*(t-1)/2:新加的边互相之间也会有连边
//连边的大小[j+1,k]:k-j+1种方案数
}
}
}
cout<<dp[n-1][k];
}
signed main()
{
int T=1;
//cin>>T;
while(T--) solve();
}
solution 2:
- 分析见上文的“大佬”
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=255, mo=998244353;
int ksm(int a,int b,int p=mo)
{
int res=1;
while(b)
{
if(b&1) res=res*a%p;
b>>=1; a=a*a%p;
}
return res;
}
int inv[N], pw[N][N*N];
void init(int n=N-3)
{
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) inv[i]=(mo-mo/i)*inv[mo%i]%mo;
for(int i=2;i<=n;i++) inv[i]=inv[i]*inv[i-1]%mo;
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n*n;j++) pw[i][j]=ksm(i,j);
}
}
int dp[N][N];
void solve()
{
init();
int n,k;
cin>>n>>k;
dp[0][0]=1;
for(int i=1;i<=n;i++) for(int j=1;j<=k;j++)
for(int p=0;p<i;p++) for(int t=0;t<j;t++)
{
(dp[i][j]+=dp[p][t]*pw[k-j+1][(p+i-1)*(i-p)/2]%mo*inv[i-p])%=mo;
}
int ans=0;
for(int i=1;i<=k;i++)
{
(ans+=dp[n-1][i])%=mo;
}
for(int i=2;i<n;i++) ans=ans*i%mo;
cout<<ans<<"\n";
}
signed main()
{
int T=1;
//cin>>T;
while(T--) solve();
}