对答案一时爽c语言,【题解】2021年牛客寒假集训营第一场题解

Updated:B(括号)的数据已经加强,大家可以再次提交试试(不影响rating和排名)

Level 0 对答案一时爽

对标cf难度:900

知识点:贪心

签到题。最小值显然是0。最大值只需要找到有多少答案牛妹和牛牛是一样的,用题目总数加上这个数即可。

#include

#include

#include

using namespace std;

#define ll long long

int n;

int main(){

int i,j;

string a,b;

cin>>n;

cin.get();

getline(cin, a, '\n');

getline(cin, b, '\n');

a.erase(remove_if(a.begin(), a.end(), ::isspace), a.end());

b.erase(remove_if(b.begin(), b.end(), ::isspace), b.end());

int cnt=0;

for(i=0;i

cout<

}

level 1 括号

对标cf难度:1300

知识点:构造、贪心

注意到题目要求字符串长度不超过

equation?tex=10%5E5&preview=true,而

equation?tex=%5Csqrt%7B10%5E9%7D&preview=true大概是三万多不到4万,所以可以在8万以内完成构造。

一种简单的构造方式是这样:找到一个数

equation?tex=i&preview=true,求出

equation?tex=k%2Fi&preview=true 的商

equation?tex=a&preview=true和余数

equation?tex=b&preview=true,那么则有

equation?tex=a*i%2Bb%3Dk&preview=true 。所以先用

equation?tex=i&preview=true个左括号,再用

equation?tex=a&preview=true个右括号,构成的字符串有

equation?tex=a*i&preview=true个括号对。之后在第

equation?tex=b&preview=true个左括号的后面插入一个右括号,就正好增加了

equation?tex=b&preview=true个括号对,符合题目要求。

大概长这个样子:

(((....((()((((...((())))....)))))

注意要特判k=0的情况,不要输出空串。

#include

using namespace std;

int main(){

int n,i;

cin>>n;

if (n == 0) {

cout << ")(" << endl;

}

else {

int p=sqrt(n);

int c=n/p,y=n%p;

for(i=0;i

printf(")");

for(;i

for(i=0;i

}

}

level 2 限制不互素对的排列

对标cf难度:1500

知识点:构造、数学

观察到

equation?tex=k&preview=true不超过

equation?tex=n&preview=true的一半,那么就简单了。

由于不大于

equation?tex=n&preview=true的所有正整数***有

equation?tex=n%2F2&preview=true个偶数(向下取整),那么如果k

如果k=n/2,那么有一个方法是,先取出所有的偶数,除了6以外依次排列,然后6后面接一个3(6和3显然不互素),然后3后面接1、5、7...依次从小到大。

举个例子,当n=10,k=5时,构造的结果是这样的:

2 4 8 10 6 3 1 5 7 9

要注意特判

equation?tex=n%20%5Cleq%205&preview=true的情况,因为n=5,k=2的时候无法在6后面接一个3了(不存在正整数6),所以无解。

ps:如果

equation?tex=k%3En%2F2&preview=true 的时候怎么构造?

#include

using namespace std;

int tong[100010];

int main(){

// freopen("13.in","r",stdin);

// freopen("13.out","w",stdout);

int n,k,i;

cin>>n>>k;

if(n<6){

if(k==n/2)cout<

else{

cout<<2;

tong[2]=1;

int i=4;

while(k--)cout<

for(i=1;i<=n;i++)if(!tong[i])cout<

}

}

else{

if(k==n/2){

for(i=2;i<=n;i+=2){

if(i!=6)cout<

}

cout<<6<

tong[6]=tong[3]=1;

for(i=1;i<=n;i+=2){

if(!tong[i])cout<

}

}

else{

cout<<2;

tong[2]=1;

int i=4;

while(k--)cout<

for(i=1;i<=n;i++)if(!tong[i])cout<

}

}

}

level 2 一群小青蛙呱蹦呱蹦呱

对标cf难度:1500

知识点:数论

我们可以发现,到最后剩余的数一定是不能表示为素数幂形式的数。

因此可以对每个素数对最终答案的贡献分别计算。

对于素数2而言,最大的贡献是

equation?tex=2%5Ek*3&preview=true(后面无法找到有

equation?tex=k%2B1&preview=true个2的贡献)。

对于大于2的素数p而言,最大的贡献是

equation?tex=p%5Ek*2&preview=true(后面无法找到有

equation?tex=k%2B1&preview=true个p的贡献)。

先线性筛出7.5e7以内的所有素数,然后统计每个素数的贡献后相乘即可。

#include

using namespace std;

#define N 80010000

#define ll long long

int num[N], prim[5000060];

int pn = 0;

void table(){

memset(num, -1, sizeof(num));

for(int i = 2;i < N;i++){

if(num[i]) prim[pn++] = i;

for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){

num[i*prim[j]] = 0;

if(i % prim[j] == 0) break;

}

}

}

int main(){

table();

int i;

int n;

ll res=1,mod=1e9+7;

cin>>n;

if(n<6){cout<

for(i=1;prim[i]<=n/2;i++){

ll p=prim[i],temp=1;

while(temp*p<=n/2)temp*=p;

res=res*temp%mod;

}

ll temp2=1;

while(temp2*2<=n/3)temp2*=2;

res=res*temp2%mod;

cout<

}

level 3 点一成零

对标cf难度:1700

知识点:并查集

假设连通块数量为n,那么总方案数就是

equation?tex=n!*%5Cprod%20(%E6%AF%8F%E4%B8%AA%E8%BF%9E%E9%80%9A%E5%9D%97%E5%A4%A7%E5%B0%8F)&preview=true

每次操作有可能增加或减少连通块的数量,并改变连通块的大小,用并查集维护即可。

#include

using namespace std;

#define ll long long

int fa[250010];

int kdm[250020];

string a[505];

int n;

int mod=1e9+7;

ll power(ll a,ll b){

ll res=1;

while(b){

if(b&1)res=res*a%mod;

b>>=1;

a=a*a%mod;

}

return res;

}

ll inv(ll x){

return power(x,mod-2);

}

int f(int x){

if(fa[x]==x)return x;

return f(fa[x]);

}

void uni(int x,int y){

int p=f(x),q=f(y);

if(p==q)return;

if(kdm[p]

fa[p]=q;

kdm[q]+=kdm[p]+1;

}

else {

fa[q]=p;

kdm[p]+=kdm[q]+1;

}

}

int visited[505][505];

void dfs(int x,int y){

visited[x][y]=1;

if(x>0&&!visited[x-1][y]&&a[x-1][y]=='1')dfs(x-1,y);

if(x

if(y>0&&!visited[x][y-1]&&a[x][y-1]=='1')dfs(x,y-1);

if(y

}

int main(){

// freopen("10.in","r",stdin);

// freopen("10.out","w",stdout);

int i,j;

cin>>n;

for(i=0;i>a[i];

for(i=0;i

for(i=0;i

for(j=0;j

if(j

uni(i*n+j,i*n+j+1);

}

if(i

uni(i*n+j,(i+1)*n+j);

}

}

}

int cnt=0;

ll res=1;

for(i=0;i

for(j=0;j

if(a[i][j]=='1'&&!visited[i][j]){

cnt++;

// cout<

res=res*(kdm[f(n*i+j)]+1)%mod;

dfs(i,j);

}

}

}

// cout<

for(i=1;i<=cnt;i++)res=res*i%mod;

// cerr<

int q;

cin>>q;

while(q--){

int x,y;

cin>>x>>y;

if(a[x][y]=='1'){

cout<

}

else{

int temp=1;

cnt++;

res=res*cnt%mod;

// cerr<

a[x][y]='1';

if(x>0&&a[x-1][y]=='1'&&f(n*(x-1)+y)!=f(n*x+y)){

res=res*inv(kdm[f(n*(x-1)+y)]+1)%mod;

temp+=kdm[f(n*(x-1)+y)]+1;

uni(n*(x-1)+y,n*x+y);

res=res*inv(cnt)%mod;

cnt--;

}

// cerr<

if(x

res=res*inv(kdm[f(n*(x+1)+y)]+1)%mod;

// cout<

temp+=kdm[f(n*(x+1)+y)]+1;

uni(n*(x+1)+y,n*x+y);

res=res*inv(cnt)%mod;

cnt--;

}

// cerr<

if(y>0&&a[x][y-1]=='1'&&f(n*x+y-1)!=f(n*x+y)){

res=res*inv(kdm[f(n*x+y-1)]+1)%mod;

temp+=kdm[f(n*x+y-1)]+1;

uni(n*x+y-1,n*x+y);

res=res*inv(cnt)%mod;

cnt--;

}

// cerr<

if(y

res=res*inv(kdm[f(n*x+y+1)]+1)%mod;

temp+=kdm[f(n*x+y+1)]+1;

uni(n*x+y+1,n*x+y);

res=res*inv(cnt)%mod;

cnt--;

}

// cout<

res=res*temp%mod;

cout<

}

}

}

level 3 红和蓝

对标cf难度:1700

知识点:树、搜索、dp

可以先树形dp预处理出每个节点子树的节点个数。那么当且仅当每个节点满足以下条件有解:

若当前节点x与父节点颜色相同,那么它的子节点子树大小必须为偶数,子节点颜色和x不同。

若当前节点x与父节点颜色不同,那么它的子节点子树大小一定有且仅有一个奇数、其他的均为偶数。x的“奇数大小子树”的那个子节点颜色和x相同,其他都和x不同。

#include

using namespace std;

vectorg[200020];

int dp[200020];

int su(int x,int pr){

int i,sum=1;

for(i=0;i

if(g[x][i]!=pr){

sum+=su(g[x][i],x);

}

}

return dp[x]=sum;

}

char out[200020];

int jud=0;

char f(char c){

if(c=='R')return 'B';

return 'R';

}

void dfs(int x,int pr,char c){

if(jud)return;

out[x]=c;

int cnt=0,i;

for(i=0;i

if(g[x][i]!=pr){

cnt+=dp[g[x][i]]&1;

}

}

if(out[x]==out[pr]){

if(cnt!=0){jud=1;return;}

for(i=0;i

if(g[x][i]!=pr){

dfs(g[x][i],x,f(c));

}

}

}

else {

if(cnt!=1){jud=1;return;}

for(i=0;i

if(g[x][i]!=pr){

if(dp[g[x][i]]&1)dfs(g[x][i],x,c);

else dfs(g[x][i],x,f(c));

}

}

}

}

int main(){

int n,i;

cin>>n;

for(i=0;i

int x,y;

cin>>x>>y;

g[x].push_back(y);

g[y].push_back(x);

}

dp[1]=su(1,-1);

// for(i=1;i<=n;i++)cout<

out[0]='B';

dfs(1,0,'R');

if(jud)cout<

else for(i=1;i<=n;i++)cout<

}

/*

6

1 2

2 3

3 4

3 5

5 6

*/

level 4 幂塔个位数的计算

对标cf难度:2100

知识点:找规律、欧拉降幂(划掉)

计算a↑↑n

当n为1时,直接输出a的个位数即可。

当n=2时,如果a的个位数是2、3、7、8,那么需要观察a的十位数是奇数还是偶数。因为

equation?tex=a%E2%86%91%E2%86%912%3Da%5Ea&preview=true,而2、3、7、8的幂的个位数是4个一循环,所以只用观察a模4是2还是0就行。

如果a的个位数是其他的,那么可以直接输出答案:a的个位数是0 1 5 6 9输出本身即可。a个位数是4则输出6。

当n大于2时,由于

equation?tex=a%E2%86%91%E2%86%91n%3Da%5E%7Ba%E2%86%91%E2%86%91(n-1)%7D&preview=true,而如果a是偶数,

equation?tex=a%E2%86%91%E2%86%91(n-1)&preview=true模4的值是确定的,所以

equation?tex=a%E2%86%91%E2%86%91n&preview=true的个位数也是确定的。而如果a是奇数(特指个位数是3和7),那么

equation?tex=a%E2%86%91%E2%86%91(n-1)&preview=true模4取决于

equation?tex=a&preview=true模4的值。如果

equation?tex=a&preview=true模4为1,那么

equation?tex=a%E2%86%91%E2%86%91(n-1)&preview=true模4也是1,此时a的个位数是3和7的话,

equation?tex=a%E2%86%91%E2%86%91n&preview=true的个位数也是3和7,否则应为7和3。

a的个位数是{0,1,2,3,4,5,6,7,8,9}时,对应的

equation?tex=a%E2%86%91%E2%86%91n&preview=true的个位数为{0,1,6,7,6,5,6,3,6,9}。

不过这道题也可以欧拉降幂直接秒掉,但由于我欧拉降幂不是很熟,所以这里就不讲解了,想学习的同学可以自行百度。

#include

using namespace std;

#define ll long long

int out[10]={0,1,6,7,6,5,6,3,6,9};

int main(){

ll a,b;

string A,B;

cin>>A>>B;

if(B.length()==1&&B[B.length()-1]=='1'){

cout<

return 0;

}

a=(A[A.length()-1]-'0')%10;

if(A[A.length()-1]=='3'||A[A.length()-1]=='7'){

if(A.length()==1||(A[A.length()-2]-'0')%2==0){

cout<

}

else{

cout<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值