硬币求和 scoins
【问题描述】
有一排
n
n
n个纵截面积为
1
1
1的硬币。
这里硬币可以抽象为一个竖立着的圆柱,
纵截面积就是圆柱的左视图面积。
每个硬币面值不一样,第
i
i
i个硬币面值是
i
i
i。
面值越大的硬币的底面圆面积当然应该越大。
具体地,面值为
i
i
i的硬币的底面圆面积为
i
i
i个单位圆的面积;
对于所有硬币的底面圆面积正比于面值。
现在请将
n
n
n个硬币摞成一座塔,
要求相邻的硬币面值差不超过 。
求这座塔的最小高度。请下取整输出。
由于浮点数存在较大的精度误差,只要误差不超过
∣
1
∣
|1|
∣1∣即可。
样例
2
0
题解
出题人原汁原味代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rint register int
inline ll rf(){ll r;int s=0,c;for(;!isdigit(c=getchar());s=c);for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);return s^45?r:-r;}
int main(){freopen("scoins.in","r",stdin), freopen("scoins.out","w",stdout); ll n = rf(), c = sqrtl(n+1.9); return !printf("%lld\n",(c-(c*c>n+1))-1);}
}
汉诺塔 hanoi
【问题描述】
给定一个有n个盘子的m阶汉诺塔(有m个柱子),求最小步数。
【输入格式】
第一行输入一个正整数T代表数据组数。接下来
T
T
T行每行两个正整数
n
n
n和
m
m
m 。
T
T
T、
n
n
n、
m
m
m均小于
1500
1500
1500
【输出格式】
对于每组数据,输出一行一个数字表示最少所需步数。
如果无论如何都无法达到目标,输出
N
o
No
No
S
o
l
u
t
i
o
n
Solution
Solution 。
【输入输出样例】
5
5 3
5 4
31
13
题解
下方第六行的公式应该是
m
i
n
min
min
出题人原汁原味代码
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1500
#define ll unsigned long long
#define INFLL 0x3f3f3f3f3f3f3f3fllu
#define rint register int
inline int rf(){int r;int s=0,c;for(;!isdigit(c=getchar());s=c);for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);return s^45?r:-r;}
int n, m, T; ll f[MAXN+5][MAXN+5]; vector<int> A[MAXN+5];
inline void Mul2(vector<int> &A){A.push_back(0); A[0] *= 2; for(int i = 1; i < (int)A.size(); A[i] = (A[i]<<1)+A[i-1]/10, A[i-1] %= 10, i++); if(!A.back()) A.pop_back();}
int main()
{
freopen("hanoi.in","r",stdin); freopen("hanoi.out","w",stdout);
n = MAXN; m = MAXN; A[1].assign(1,2); for(rint i = 2; i <= n; A[i] = A[i-1], --A[i-1][0], Mul2(A[i++])); --A[n][0];
memset(f,0x3f,sizeof f); memset(f[1]+1,0,n<<3); f[2][1] = 1; {ll s = 2; for(rint i = 1; i <= n; f[3][i] = min(f[3][i],s-1), s = min(s<<1,INFLL+1), i++);}
for(rint i = 4, j, k; i <= m; i++) for(f[i][1] = 1, j = 2, k = 1; j <= n; f[i][j] = f[i-1][j-k]+(f[i][k]<<1), j++)
for(; k<j-1 && f[i-1][j-k]+(f[i][k]<<1) > f[i-1][j-k-1]+(f[i][k+1]<<1); ++k);
for(T = rf(); T--; )
{
n = rf(); m = rf(); if(m==1){puts("0"); continue;} if(m==2){puts(n>1?"No Solution":"1"); continue;}
if(m==3){for(rint i = A[n].size()-1; ~i; putchar(A[n][i]+'0'), i--); putchar('\n'); continue;} printf("%llu\n",f[m][n]);
} return 0;
}
随机子树 tree
【问题描述】
有一棵n个点的树。
每天,随机选择一个连通块(一棵子树),从一个点出发走向另一个点的最短路径巡视,巡视走过的距离是两个点之间唯一最短路径包含的边数。
巡视距离太短,起不到有效检查;巡视距离太长太累。
问: 均匀随机选择一个连通块,有多大概率这一天巡视时有可能走过的最长距离也一定在
[
L
,
R
]
[L,R]
[L,R]之间。
【输入格式】
只有一行输入三个正整数
n
,
L
,
R
n,L,R
n,L,R。
接下来
n
−
1
n-1
n−1行,每行两个正整数
u
,
v
u,v
u,v表示
u
,
v
u,v
u,v之间有一条边。保证输入是一棵树。
【输出格式】
只有一行输出一个整数。为
m
o
d
998244353
mod 998244353
mod998244353意义下的概率。即如果答案可以表示成最简分数
p
q
\frac{p}{q}
qp
请输出 p p p ∗ * ∗ q − 1 q^{-1} q−1 m o d mod mod 998244353 998244353 998244353,其中 q − 1 q^{-1} q−1代表模意义下逆元。
【输入输出样例】
5 2 3
1 2
1 3
3 4
3 5
528482305
题解
出题人原汁原味代码
#include <bits/stdc++.h>
using namespace std;
#define MAXN 200000
#define MOD 998244353
#define lc(p) (p<<1)
#define rc(p) (p<<1|1)
#define ad(p) t[p][0]
#define ml(p) t[p][1]
#define mid (lef+rig>>1)
#define MUL(p,k) (k^1 ? ad(p) = 1ll*ad(p)*k%MOD, ml(p) = 1ll*ml(p)*k%MOD : 0)
#define LZ(p) (MUL(lc(p),ml(p)), MUL(rc(p),ml(p)), ml(p) = 1)
#define PS(p) (ad(p) = (ad(lc(p))+ad(rc(p)))%MOD)
#define Auto(v,j) for(vector<int>::iterator j = v.begin(); j != v.end(); j++)
#define rint register int
inline int rf(){int r;int s=0,c;for(;!isdigit(c=getchar());s=c);for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);return s^45?r:-r;}
inline int fxp(int s, int n=MOD-2){int a=1;for(;n;n&1?a=1ll*a*s%MOD:0,s=1ll*s*s%MOD,n>>=1);return a;}
int n, Le, Ri, K, Ans, t[524288][2], d[MAXN+5], md[MAXN+5], pos[MAXN+5]; vector<int> e[MAXN+5]; inline bool cmp(int x, int y){return md[x]>md[y];}
void BD(int p, int lef, int rig){ml(p)=1,ad(p)=0,lef^rig?BD(lc(p),lef,mid),BD(rc(p),mid+1,rig),0:0;}
void AD(int p, int lef, int rig, int x, int v){lef^rig?LZ(p),x<=mid?AD(lc(p),lef,mid,x,v):AD(rc(p),mid+1,rig,x,v),PS(p):ad(p)=(ad(p)+v)%MOD;}
int QU(int p, int lef, int rig, int L, int R){return L^lef||R^rig?LZ(p),((L<=mid?QU(lc(p),lef,mid,L,min(mid,R)):0)+(R>mid?QU(rc(p),mid+1,rig,max(L,mid+1),R):0))%MOD:ad(p);}
void MU(int p, int lef, int rig, int L, int R, int k){L^lef||R^rig?LZ(p),L<=mid?MU(lc(p),lef,mid,L,min(mid,R),k),0:0,R>mid?MU(rc(p),mid+1,rig,max(L,mid+1),R,k),0:0,PS(p):MUL(p,k);}
void DFS1(int p, int fa){if(fa) e[p].erase(find(e[p].begin(),e[p].end(),fa)); md[p] = d[p] = d[fa]+1; Auto(e[p],j) DFS1(*j,p), md[p] = max(md[p],md[*j]);}
void DFS2(int p){sort(e[p].begin(),e[p].end(),cmp); pos[p] = ++n; Auto(e[p],j) DFS2(*j);}
void DFS3(int p){
static int k[MAXN+5], f[MAXN+5]; static map<int,int> G; int X = md[p]-d[p], Y, v, _; AD(1,1,n,pos[p],1);
Auto(e[p],j){DFS3(v=*j); if(j==e[p].begin()) continue; Y = md[v]-d[v]; G.clear(); G[0] = 1; G[X+1] = 0; _ = 0;
for(rint y = 0; y <= Y && y < K; k[y] = QU(1,1,n,pos[p],pos[p]+min(y,K-y-1)), f[y] = QU(1,1,n,pos[v]+y,pos[v]+y), y++);
for(rint y = 0; y <= Y && y < K; y+1<K-y?(G[y+1]+=f[y])%=MOD,(G[min(K-y,X+1)]+=MOD-f[y])%=MOD:0, y++);
for(map<int,int>::iterator a = G.begin(), b = ++G.begin(); b != G.end(); a++, b++)
_ = (_+a->second)%MOD, MU(1,1,n,pos[p]+a->first,pos[p]+b->first-1,_);
for(rint y = 0; y <= Y && y < K; AD(1,1,n,pos[p]+y+1,1ll*k[y]*f[y]%MOD), y++);
} Ans = (Ans+QU(1,1,n,pos[p],pos[p]+min(K,X)))%MOD;
}
int Work(int _K){BD(1,1,n); K = _K; Ans = 0; DFS3(1); return Ans;}
int main(){
freopen("tree.in","r",stdin), freopen("tree.out","w",stdout);
n = rf(); Le = rf(); Ri = rf(); for(rint i = 1, u, v; i < n; u = rf(), v = rf(), e[u].push_back(v), e[v].push_back(u), i++);
DFS1(1,0); n = 0; DFS2(1); return !printf("%d\n",1ll*fxp(Work(n))*(Work(Ri)-Work(Le-1)+MOD)%MOD);
}
出题人代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=510;int a[N][N],b[N][N],s[N][N];
inline int _init(int n)
{
rep(i,1,n) rep(j,1,n) if((i-2*j)%5==0) s[i][j]=1;
rep(i,1,n) rep(j,1,n) s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
return 0;
}
inline int S(int xl,int xr,int yl,int yr) { return s[xr][yr]-s[xl-1][yr]-s[xr][yl-1]+s[xl-1][yl-1]; }
int main()
{
freopen("landmine.in","r",stdin); freopen("landmine.out","w",stdout);
int n=inn(),m=inn(),rev=0,ans=0;if(n>m) swap(n,m),rev=1;
if(n<5) { ans=n*(m/5);rep(i,1,n) rep(j,1,m) a[i][j]=!(j%5); }
else{
int t=10;ans=n*m/5,_init(max(n,m)+t);
rep(i,1,t) rep(j,1,t) if(S(i,i+n-1,j,j+m-1)==ans)
{
rep(p,1,n) rep(q,1,m) a[p][q]=S(i+p-1,i+p-1,j+q-1,j+q-1);break;
}
}
printf("%d\n",ans);
if(rev) { swap(n,m);rep(i,1,n) rep(j,1,m) b[i][j]=a[j][i]; }
else rep(i,1,n) rep(j,1,m) b[i][j]=a[i][j];
rep(i,1,n) rep(j,1,m) a[i][j]=b[i][j];
rep(i,1,n) { rep(j,1,m) printf("%d",a[i][j]);printf("\n"); }
rep(i,1,n) rep(j,1,m)//check if it's right ( RE if wrong )
{
int zc;
zc=0;if(i+4<=n) rep(k,0,4) zc+=(a[i+k][j]==0);assert(zc<5);
zc=0;if(j+4<=m) rep(k,0,4) zc+=(a[i][j+k]==0);assert(zc<5);
zc=0;if(i+4<=n&&j+4<=m) rep(k,0,4) zc+=(a[i+k][j+k]==0);assert(zc<5);
zc=0;if(i+4<=n&&j-4>=1) rep(k,0,4) zc+=(a[i+k][j-k]==0);assert(zc<5);
}
return 0;
}
同班大佬的题解
如果
m
,
n
m,n
m,n其中一个小于5,那么必然不会在短边和斜方向上产生“
5
5
5连”,那么只需要考虑长边就行,随便画一组数据,发现只要逢5出现一个1即可。
如果两者都大于五,就需要思考一种策略。观察样例,如果我们把
“
5
∗
5
”
“5*5”
“5∗5”作为一个单位矩阵,我们只需要用单位矩阵填充这个大矩形即可,因为单位矩阵相同,那么在横纵上必然不会出现“
5
5
5连”的情况,只需要保证斜边上不会出现“
5
5
5连”。
很好,思考出题解了,我们根据样例构建单位矩阵,交上去评测,WA掉了,很好!
为什么呢?因为单位矩阵是不能满足斜边无“
5
5
5连”的,接着就要手玩单位矩阵辽,玩着玩着单位矩形就出来了……
还有一个矩阵中几个
1
1
1的问题,因为每25个方格的单位矩阵中会有5个1,这是显然的,所以上面特判的公式是
m
∗
n
/
5
m*n/5
m∗n/5,其他情况要用一个cnt记录。
根据题解写的代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n, m, cnt = 0;
int a[505][505]={};
int b[5]={1,4,2,5,3};
int main(){
scanf("%d%d", &n, &m);
if(n < 5) {
printf("%d\n", m*n/5);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(j % 5 == 0) printf("1");//每出现五个,就添加一个1,保证不出现“5连”
else printf("0");
}
printf("\n");
}
return 0;
}//n小于5的情况,下面同样方法特判m小于5
if(m < 5) {
printf("%d\n", m*n/5);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(i % 5 == 0) printf("1");
else printf("0");
}
printf("\n");
}
return 0;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
a[i][j] = 0;
for(int i = 1; i <= n; i++)
for(int j = b[ i%5 ]; j <= m; j +=5){
a[i][j] = 1;
cnt++;
}//单位矩阵的复制黏贴,好快乐!
printf("%d\n",cnt);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++)
printf("%d", a[i][j]);
printf("\n");
}//输出
return 0;
}
出题人代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int rf(){int r;int s=0,c;for(;!isdigit(c=getchar());s=c);for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);return s^45?r:-r;}
const int N=5000010;const lint inf=LLONG_MIN/100;const db eps=1e-9;
int L[N];
namespace GETL{
// f[i] trans from [ L_i, i ), f[i] = max_{L_i<=j<i} f[j]+calc(i-j), calc(x)=x*(x-1)/2
inline int getL(int n)
{
rep(i,1,n) L[i]=rf();
assert(L[1]==0);
rep(i,1,n-1) assert(L[i]<=L[i+1]);
return 0;
}
}
inline int dcmp(db x) { return (x<-eps)?-1:(x>eps); }
struct Line{
lint k,b;Line(lint _k=0,lint _b=inf) { k=_k,b=_b; }
inline lint operator()(lint x)const { return k*x+b; }
inline db getis(const Line &L)const { return -((db)b-L.b)/(k-L.k); }
};
struct Queue{
int t;Line f[N];inline int clear() { return t=0; }
inline int add(Line F) { while(t>1&&dcmp(F.getis(f[t])-f[t].getis(f[t-1]))>=0) t--;f[++t]=F;return 0; }
inline lint query(lint x) { if(!t) return inf;while(t>1&&f[t](x)<=f[t-1](x)) t--;return f[t](x); }
}q;int l[N],r[N];lint f[N];
int main()
{
freopen("jump.in","r",stdin); freopen("jump.out","w",stdout);
int n=rf(),bc=0;GETL::getL(n);
for(int i=0,j=0;i<n;i=++j) { while(j+1<n&&L[j+2]<=i) j++;l[++bc]=i,r[bc]=j; }
f[0]=0;rep(i,1,n) f[i]=inf;
rep(i,1,bc)
{
q.clear();int k=l[i];
for(int j=r[i]+1;j>l[i];j--)
{
while(k>L[j]) k--,q.add(Line(k,f[k]+k*(k+1ll)/2));
f[j]=max(f[j],q.query(-j)+j*(j-1ll)/2);
}
q.clear();
rep(j,l[i]+1,r[i]+1) q.add(Line(-(j-1),f[j-1]+(j-1ll)*j/2)),f[j]=max(f[j],q.query(j)+j*(j-1ll)/2);
}
return !printf("%lld\n",f[n]<<1);
}
出题人代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define mod 998244353
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int rf(){int r;int s=0,c;for(;!isdigit(c=getchar());s=c);for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);return s^45?r:-r;}
const int N=500010,K=22;
int np[N],p[N],C[K<<1][K<<1],f[K][N],mnp[N],zs[N],clc[K][K];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int prelude(int n,int mxk)//seems that O(n(lgn)^2) is faster then O(nlgn) QwQ
{
rep(i,0,mxk) f[i][1]=1;
rep(i,0,2*mxk) C[i][0]=1;
rep(i,1,2*mxk) rep(j,1,i) C[i][j]=C[i-1][j-1]+C[i-1][j],(C[i][j]>=mod?C[i][j]-=mod:0);
rep(i,0,mxk) rep(j,0,mxk) clc[i][j]=C[i+j][i];
for(int i=2,c=0;i<=n;i++)
{
if(!np[i]) { p[++c]=i,mnp[i]=i,zs[i]=1;rep(j,0,mxk) f[j][i]=j+1; }
rep(j,1,c&&p[j]<=n/i)
{
int x=p[j]*i;np[x]=1;
if(i%p[j]!=0) { mnp[x]=p[j];rep(k,0,mxk) f[k][x]=f[k][i]*(k+1ll)%mod; }
else{
mnp[x]=mnp[i]*p[j];int t=x/mnp[x];
if(x==mnp[x]) { zs[x]=zs[i]+1;rep(k,0,mxk) f[k][x]=clc[k][zs[x]]; }
else rep(k,0,mxk) f[k][x]=(lint)f[k][t]*f[k][mnp[x]]%mod;break;
}
}
}
rep(i,0,mxk) rep(j,1,n) f[i][j]+=f[i][j-1],(f[i][j]>=mod?f[i][j]-=mod:0);
return 0;
}
int y[K],pre[K],suf[K],fi[K];
inline int solve(int *y,int n,int p)
{
if(p>=mod) p%=mod;if(p<=n) return y[p];int ans=0;
pre[0]=p,suf[n]=p-n;rep(i,1,n) pre[i]=(lint)pre[i-1]*(p-i)%mod;
for(int i=n-1;i>=0;i--) suf[i]=(lint)suf[i+1]*(p-i)%mod;
rep(i,0,n)
{
int pr=(i>0?pre[i-1]:1),sf=(i<n?suf[i+1]:1);
if((n-i)&1) ans=(ans-(lint)y[i]*pr%mod*sf%mod*fi[i]%mod*fi[n-i])%mod,(ans<0?ans+=mod:0);
else ans=(ans+(lint)y[i]*pr%mod*sf%mod*fi[i]%mod*fi[n-i])%mod;
}
return ans;
}
int main()
{
freopen("easy.in","r",stdin); freopen("easy.out","w",stdout);
int n=rf(),mxk=rf(),q=rf();prelude(n,mxk=20);
rep(i,fi[0]=1,mxk) fi[i]=(lint)fi[i-1]*fast_pow(i,mod-2)%mod;
while(q--)
{
int L=rf(),R=rf(),k=rf()-1;
rep(i,0,mxk) y[i]=f[i][R]-f[i][L-1],(y[i]<0?y[i]+=mod:0);
printf("%d\n",solve(y,mxk,k));
}
return 0;
}