咕咕了好久,AC怪终于想起来WA补题了,log2r终于开始尝试写博客啦QAQ
(以下题目顺序为自己做题时体感难度排序 )
Description
n n n道单选题,每题正确得 1 分,错误得0分。
已知两人每题的选项。求两人可能的最大得分和、最小得分和。
Solution
签到,最小得分为0,最大得分在所有题目两人中至少一人答案正确时取到。
#include
#include
#include
#include
#include
#include
#define MAXN 100+5
using namespace std;
inline int Fread(){
int val=0;
bool sign=false;
char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && (ch^'-'));
val=(sign=!(ch^'-'))?0:ch^48;
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+(ch^48);
return sign?~val+1:val;
}
char S[MAXN],T[MAXN];
int n,ans=0;
int main(){
n=Fread();
for(int i=1;i<=n;++i) scanf(" %c",&S[i]);
for(int i=1;i<=n;++i){
scanf(" %c",&T[i]);
ans+=(S[i]==T[i])?2:1;
}
printf("%d 0",ans);
return 0;
}
Description
求一个球心在棱长为 a a a的正三棱锥中心,半径为 r r r的球与正三棱锥截交面的面积。
Solution
高中立体几何,所形成的四个截交面可能为空、圆、圆和正三角形截交、正三角形,分类讨论即可。
#include
#include
#include
#include
#include
#include
#define pi acos(-1.0)
using namespace std;
int main(){
double a,r;
scanf("%lf%lf",&a,&r);
double dis1=sqrt(6.0)*a/12.0,dis2=sqrt(2.0)*a/4.0,dis3=sqrt(6.0)*a/4.0,ans=0.0;
if(r<dis1){
printf("0.00000");
return 0;
}
if(r<dis2) ans=pi*(r*r-dis1*dis1);
else if(r<dis3){
double r_=sqrt(r*r-dis1*dis1),dis=sqrt(3.0)*a/6.0,cur=3.0*(pi/3.0-acos(dis/r_))*r_*r_;
ans=cur+3.0*dis*sqrt(r_*r_-dis*dis);
}
else ans=sqrt(3.0)*a*a/4.0;
ans*=4.0;
printf("%.5lf",ans);
return 0;
}
Description
构造非空括号字符串,恰好包含 k k k个不同合法括号对。
字符串长度 0 < l ≤ 1 e 5 , 0 ≤ k ≤ 1 e 9 0
Solution
1、 依次由 L L L个"(“和 R R R个”)“组成的字符串构成的不同合法括号对数目为 L × R L×R L×R。
2、 在上述序列中前 L L L个位置中第 m m m个位置插入一个”)",构成的不同合法括号对数目为 L × R + m L×R+m L×R+m。
因此,只需找到 k = L × R + m ( m ≤ L , L + R + 1 ≤ 1 e 5 ) k=L×R+m(m≤L,L+R+1≤1e5) k=L×R+m(m≤L,L+R+1≤1e5)即可。
为使 L + R L+R L+R尽可能小,且 m ≤ L m≤L m≤L,可取:
最后特判一下 k = 0 k=0 k=0的情况。
#include
#include
#include
#include
#include
#include
#define MAXN 100+5
using namespace std;
inline int Fread(){
int val=0;
bool sign=false;
char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && (ch^'-'));
val=(sign=!(ch^'-'))?0:ch^48;
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+(ch^48);
return sign?~val+1:val;
}
int main(){
int k=Fread();
if(!k){
printf("(");
return 0;
}
int l=sqrt(k),r=k/l,mod=k-l*r;
for(int i=1;i<=mod;++i) printf("(");
printf(")");
for(int i=mod+1;i<=l;++i) printf("(");
for(int i=1;i<=r;++i) printf(")");
return 0;
}
Description
构造 1 ~ n 1~n 1~n的一种排列,使得恰好 k k k对相邻两数 g c d gcd gcd大于1。
2 ≤ n ≤ 1 e 5 , 0 ≤ k ≤ n / 2 2≤n≤1e5,0≤k≤n/2 2≤n≤1e5,0≤k≤n/2。
Solution
1、 注意一下 k ≤ n / 2 k≤n/2 k≤n/2的条件,可以把 1 ~ n 1~n 1~n拆分成相邻偶数、相邻奇数和相邻整数。
2、 ( k + 1 ) (k+1) (k+1)个相邻偶数构成k个不互素对,而相邻奇数和相邻整数之间 g c d gcd gcd均为1。因此先放置(k+1)个偶数,再按顺序放置剩余的数即可。 k < n / 2 k
3、 若 k = n / 2 k=n/2 k=n/2,先按照 ( k − 1 ) (k-1) (k−1)的构造方式,然后取出排列中的6和3依次放到相邻偶数排列后,不互素对增加了1,构造完成。
4、 特判 n < 6 n<6 n<6的情况即可。
#include
#include
#include
#include
#include
#include
#define MAXN 100000+5
using namespace std;
inline int Fread(){
int val=0;
bool sign=false;
char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && (ch^'-'));
val=(sign=!(ch^'-'))?0:ch^48;
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+(ch^48);
return sign?~val+1:val;
}
int main(){
int n=Fread(),k=Fread();
if(n==2) printf(k?"-1":"1 2");
else if(n==3) printf(k?"-1":"1 2 3");
else if(n==4) printf(k==2?"-1":k==1?"2 4 1 3":"1 2 3 4");
else if(n==5) printf(k==2?"-1":k==1?"2 4 1 3 5":"1 2 3 4 5");
else if(!k){
for(int i=1;i<=n;++i) printf("%d ",i);
}
else if(k==(n>>1)){
for(int i=1;i<=k;++i)
if(i^3) printf("%d ",i<<1);
printf("6 3 1 ");
for(int i=2;i<=k-1;++i) printf("%d ",i<<1^1);
if((k<<1)^n) printf("%d ",n);
}
else{
for(int i=1;i<=k+1;++i) printf("%d ",i<<1);
for(int i=0;i<=k;++i) printf("%d ",i<<1^1);
for(int i=(((k+1)<<1)^1);i<=n;++i) printf("%d ",i);
}
return 0;
}
Description
求长度不超过 n n n,由小写字母构成,删除或不删除部分字符后可得到"us"的字符串个数。
2 ≤ n ≤ 1 e 6 2≤n≤1e6 2≤n≤1e6,答案对 1 e 9 + 7 1e9+7 1e9+7取模。
Solution
递推, f [ i ] f[i] f[i]表示长度为 i i i且符合题意的字符串个数,考虑第 ( i + 1 ) (i+1) (i+1)位产生的方案数。
1、 当前i位符合题意时,第 ( i + 1 ) (i+1) (i+1)位随意填充,总方案数 26 × f [ i ] 26×f[i] 26×f[i]。
2、 考虑前i位不合题意,但前 ( i + 1 ) (i+1) (i+1)位符合题意。当且仅当前 i i i位含有’u’但不存在子序列"us",且第 ( i + 1 ) (i+1) (i+1)位为’s’。前 i i i位含有"u"的字符串数目为 2 6 i − 2 5 i 26^i - 25^i 26i−25i,前 i i i位存在子序列的字符串数目为 f [ i ] f[i] f[i]。总方案数 2 6 i − 2 5 i − f [ i ] 26^i - 25^i-f[i] 26i−25i−f[i]。
因此,递推方程: f [ i + 1 ] = 25 × f [ i ] + 2 6 i − 2 5 i , f [ 2 ] = 1 f[i+1]=25×f[i]+26^i - 25^i,f[2]=1 f[i+1]=25×f[i]+26i−25i,f[2]=1
#include
#include
#include
#include
#include
#include
#define ll long long
#define MAXN 1000000+5
#define MOD 1000000007
using namespace std;
inline int Fread(){
int val=0;
bool sign=false;
char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && (ch^'-'));
val=(sign=!(ch^'-'))?0:ch^48;
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+(ch^48);
return sign?~val+1:val;
}
inline ll qpow(ll x,ll k){
ll res=1ll;
for(int i=k;i;i>>=1,x=x*x%MOD)
if(i&1) res=res*x%MOD;
return res;
}
ll f[MAXN];
int main(){
int n=Fread();
ll ans=0ll;
f[2]=1;
for(int i=2;i<n;++i) f[i+1]=((f[i]*26)%MOD+qpow(26,i)%MOD-qpow(25,i)%MOD-f[i]%MOD+MOD)%MOD;
for(int i=1;i<=n;++i) ans=(ans+f[i])%MOD;
printf("%lld",ans);
return 0;
}
Description
长度为 n n n的格子里放无穷多青蛙,第 i i i只青蛙路线为以1为首项, p [ i ] p[i] p[i]为公比的等比数列,其中 p [ i ] p[i] p[i]为第 i i i大的素数,求 n n n个格子中所有未被占据格子编号的 l c m lcm lcm。
1 ≤ n ≤ 1.6 e 8 1≤n≤1.6e8 1≤n≤1.6e8,答案对 1 e 9 + 7 1e9+7 1e9+7取模。
Solution
对每个未被占据的格子进行质因数分解,考虑每个质因子对答案的贡献。
质因子对 l c m lcm lcm的贡献取决于质因子在未被占据的格子中最大次幂。
每个未被占据的格子均有至少两个质因子,因此,对于质因子2,其最大次幂为 l o g 2 [ n 3 ] log_2^{[\frac{n}{3}]} log2[3n];对于其他质因子 p p p,其最大次幂为 l o g p [ n 2 ] log_p^{[\frac{n}{2}]} logp[2n]。
最终答案 2 l o g 2 [ n 3 ] ∏ i = 2 k | p k ≤ n p i l o g p i [ n 2 ] 2^{log_{2}^{[\frac{n}{3}]}}\prod_{i=2}^{k|p_k≤n} p_i^{log_{p_i}^{[\frac{n}{2}]}} 2log2[3n]∏i=2k|pk≤npilogpi[2n]
(有被题目名称可爱到)
#include
#include
#include
#include
#include
#include
#define ll long long
#define MAXM 160000000+5
#define MAXN 10000000+5
#define MOD 1000000007
using namespace std;
inline int Fread(){
int val=0;
bool sign=false;
char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && (ch^'-'));
val=(sign=!(ch^'-'))?0:ch^48;
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+(ch^48);
return sign?~val+1:val;
}
bool vis[MAXM];
int cnt=0;
ll prime[MAXN];
inline void phi_prime(int n){
for(int i=2;i<=n;++i){
if(!vis[i]) prime[++cnt]=i;
for(int j=1;(j<=cnt && i*prime[j]<=n);++j){
vis[i*prime[j]]=true;
if(!(i%prime[j])) break;
}
}
return;
}
int main(){
int n=Fread();
phi_prime(n);
if(n<=5){
printf("empty");
return 0;
}
ll cur=1ll,ans=1ll;
while((cur<<1)<=n/3) cur=(cur<<1)%MOD;
ans=ans*cur%MOD;
for(int i=2;(prime[i] && prime[i]<=n);++i){
cur=1ll;
while(prime[i]*cur<=(n>>1)) cur=cur*prime[i]%MOD;
ans=ans*cur%MOD;
}
printf("%lld",ans);
return 0;
}
Description
给定一颗树,对树的节点 1 ~ n 1~n 1~n染红色或蓝色,使得红色节点相邻节点有且仅有一个红色节点;蓝色节点相邻节点有且仅有一个蓝色节点。
1 ≤ n ≤ 1 e 5 1≤n≤1e5 1≤n≤1e5
Solution
1、 叶节点与其父节点为同色。
2、 叶节点的父节点与其父节点的父节点为异色。
3、 若将叶节点及其父节点删除,则其父节点的父节点成为新的叶节点,新叶节点必与新叶节点的父节点同色。
因此,对于任意一个节点,当且仅当节点数目为奇数的子树个数 ≤ 1 ≤1 ≤1时,该节点可以被染色。且该节点与其父节点颜色相反当且仅当该节点子树大小为奇数。
首先第一遍dfs预处理出以每个节点为根的子树大小,顺带判断无解的情况,然后第二遍dfs从根节点进行染色。
#include
#include
#include
#include
#include
#include
#define MAXN 100000+5
using namespace std;
inline int Fread(){
int val=0;
bool sign=false;
char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && (ch^'-'));
val=(sign=!(ch^'-'))?0:ch^48;
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+(ch^48);
return sign?~val+1:val;
}
struct Edge{
int u,v,nxt;
Edge(){
nxt=-1;}
Edge(int u,int v):u(u),v(v){
}
}g[MAXN<<1];
int cnt=-1,tot[MAXN],siz[MAXN],head[MAXN],col[MAXN];
inline void add_edge(int u,int v){
g[++cnt]=Edge(u,v);
g[cnt].nxt=head[u];
head[u]=cnt;
return;
}
bool dfs1(int u,int fa){
siz[u]=1;
for(int i=head[u];~i;i=g[i].nxt)
if(g[i].v!=fa){
if(!dfs1(g[i].v,u)) return false;
siz[u]+=siz[g[i].v];
if(siz[g[i].v]&1) ++tot[u];
}
return tot[u]<=1;
}
void dfs2(int u,int fa,int cur){
col[u]=cur;
for(int i=head[u];~i;i=g[i].nxt)
if(g[i].v!=fa) dfs2(g[i].v,u,siz[g[i].v]&1?cur:cur^1);
return;
}
int main(){
memset(head,0xff,sizeof head);
int n=Fread();
for(int i=1;i<n;++i){
int u=Fread(),v=Fread();
add_edge(u,v);
add_edge(v,u);
}
if((n&1) || (!dfs1(1,-1))){
printf("-1");
return 0;
}
dfs2(1,-1,0);
for(int i=1;i<=n;++i) printf(col[i]?"R":"B");
return 0;
}
Description
给定 n × n n×n n×n的 0 − 1 0-1 0−1方阵,每次操作把一个元素均为"1"的连通块变为元素均为"0", k k k次询问,每次询问把方阵中的某个元素变为"1",求每次询问后把方阵变为0方阵的方案数。
n ≤ 500 , k ≤ 1 e 5 n≤500,k≤1e5 n≤500,k≤1e5,强制在线。
Solution
并查集维护每个连通块大小。设连通块数目为 N N N,第 i i i个连通块大小为 s i z e i size_i sizei,则方案数为 N ! ∏ i = 1 N s i z e i N!\prod_{i=1}^{N} size_i N!∏i=1Nsizei,每次查询时更新连通块大小及数目。
#include
#include
#include
#include
#include
#include
#define ll long long
#define MAXN (500+5)
#define MOD 1000000007ll
using namespace std;
inline int Fread(){
int val=0;
bool sign=false;
char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && (ch^'-'));
val=(sign=!(ch^'-'))?0:ch^48;
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+(ch^48);
return sign?~val+1:val;
}
int dx[5]={
0,1,-1,0,0};
int dy[5]={
0,0,0,1,-1};
int n,k,cnt,fa[MAXN*MAXN];
ll tot=1ll,fac[MAXN*MAXN],siz[MAXN*MAXN];
char s[MAXN][MAXN];
inline ll qpow(ll x,ll k){
ll res=1ll;
for(ll i=k;i;i>>=1,x=x*x%MOD)
if(i&1) res=res*x%MOD;
return res;
}
inline ll inv(ll x){
return qpow(x,MOD-2);
}
inline int Find(int x){
return x==fa[x]?x:fa[x]=Find(fa[x]);
}
inline void Union(int x,int y){
int rx=Find(x),ry=Find(y);
if(rx==ry) return;
tot=(tot*inv(siz[rx]))%MOD;
tot=(tot*inv(siz[ry]))%MOD;
fa[ry]=rx;
siz[rx]+=siz[ry];
tot=(tot*siz[rx])%MOD;
--cnt;
return;
}
inline bool judge(int x,int y){
return (~x) && (~y) && (x<n) && (y<n);
}
int main(){
n=Fread();
siz[0]=fac[0]=1ll;
for(int i=1;i<=n*n;++i){
fa[i]=i;
siz[i]=1ll;
fac[i]=fac[i-1]*i%MOD;
}
for(int i=0;i<n;++i){
scanf("%s",s[i]);
for(int j=0;j<n;++j)
if(!(s[i][j]^'1')){
++cnt;
for(int k=1;k<=4;++k){
int x=i+dx[k],y=j+dy[k];
if(!judge(x,y)) continue;
if(!(s[x][y]^'1')) Union(i*n+j,x*n+y);
}
}
}
k=Fread();
while(k--){
int x=Fread(),y=Fread();
if(s[x][y]^'1'){
s[x][y]='1';
++cnt;
for(int i=1;i<=4;++i){
int x_=x+dx[i],y_=y+dy[i];
if(!judge(x_,y_)) continue;
if(!(s[x_][y_]^'1')) Union(x*n+y,x_*n+y_);
}
}
printf("%lld\n",fac[cnt]*tot%MOD);
}
return 0;
}