我好菜啊

A

题意:

定义p-二进制数为2^k-p,给出n和p,求用最小个数的p-二进制数来表示n

1<=n<=10^9,-1000<=p<=1000

题解:

猜结论,答案不会很大

n可以表示成kp+s的形式,枚举k,判断(n-kp)是否能用k个2的幂构成

画一下图可以发现,如果可以构成,那么满足(n-kp)的位数<=k<=n-kp

(相当于把一颗二叉树上一个点变成两个)

证明答案不会很大:

首先(n-kp)的位数最多为30

①p>=0

显然当k超过30后,如果不满足则之后也不满足

②p<0

那么n-kp显然大于等于k

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std; long long n,s;
int p,i,j,k,l; bool pd(long long t)
{
long long T=t;
int sum=0; while (T)
{
sum+=T&1;
T>>=1;
} if (s>=sum && s<=t)
return 1;
else
return 0;
} int main()
{
// freopen("a.in","r",stdin); scanf("%I64d%d",&n,&p); while (!pd(n))
{
n-=p;
++s; if (n<0 ||s>100)
break;
} if (n>=0 && pd(n))
printf("%I64d\n",s);
else
printf("-1\n");
}

B

题意:

给出n个数和k,求(i,j)的个数(i<j),使得ai*aj=x^k

n<=10^5,2<=k<=100

题解:

能表示成x的k次方,意味着乘积质因数分解后每一位的指数%k=0

也就是(ai中p的指数+aj中p的指数)%k=0,把i或j的指数取负,变成求ai和aj质因数指数相等的(i,j)个数

可以排序搞,根据k讨论一下大质数

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
using namespace std; int a[200001];
int p[200001][66];
int P[317];
int c[200001];
int N,n,K,i,j,k,l,s,len,ls,s1,s2;
long long ans;
bool bz; bool cmp(int a,int b)
{
int i; fo(i,1,65)
if (p[a][i]<p[b][i])
return 1;
else
if (p[a][i]>p[b][i])
return 0; return 0;
} bool pd(int t)
{
int i; fo(i,1,65)
if (p[a[t]][i]!=p[a[t+1]][i])
return 0;
return 1;
} bool Cmp(int x,int y)
{
return p[x][0]<p[y][0];
} int main()
{
// freopen("b.in","r",stdin); fo(i,2,316)
{
k=1; fo(j,2,floor(sqrt(i)))
if (!(i%j))
{
k=0;
break;
} if (k)
P[++len]=i;
} scanf("%d%d",&n,&K);
fo(i,1,n)
{
scanf("%d",&l);
fo(j,1,len)
if (!(l%P[j]))
{
while (!(l%P[j]))
{
l/=P[j];
++p[i][j];
}
p[i][j]%=K;
p[i+n][j]=(K-p[i][j])%K;
} if (l>1)
{
p[i][0]=l;
p[i+n][0]=l;
}
} N=n+n;
fo(i,1,N)
a[i]=i; // fo(i,1,N)
// {
// fo(j,0,5)
// cout<<p[i][j]<<" ";
// cout<<endl;
// } sort(a+1,a+N+1,cmp); // fo(i,1,N)
// cout<<a[i]<<endl;
// fo(i,1,N)
// {
// fo(j,0,5)
// cout<<p[a[i]][j]<<" ";
// cout<<endl;
// } ls=1;
fo(i,1,N)
if (i==N || !pd(i))
{
l=0;
fo(j,ls,i)
c[++l]=a[j]; sort(c+1,c+l+1,Cmp); if (K>=3)
{
s1=0;s2=0; fo(j,1,l)
if (!p[c[j]][0])
{
if (c[j]<=n)
++s1; else ++s2;
} // fo(j,1,l)
// if (c[j]<=n)
// cout<<c[j]<<" ";
// else
// cout<<-(c[j]-n)<<" ";
// cout<<endl;
// cout<<" "<<s1*s2<<" "<<s1<<" "<<s2<<endl; ans+=(long long)s1*s2;
}
else
{
s1=0;s2=0;
fo(j,1,l)
{
if (j==1 || p[c[j]][0]==p[c[j-1]][0])
{
if (c[j]<=n)
++s1; else ++s2;
}
else
{
ans+=(long long)s1*s2; s1=0;s2=0;
if (c[j]<=n)
++s1; else ++s2;
}
}
ans+=(long long)s1*s2;
} ls=i+1;
} if (K==2)
{
fo(i,1,n)
{
fo(j,1,65)
if ((p[i][j]*2%K))
break; if (j>65)
--ans;
}
}
else
{
fo(i,1,n)
if (!p[i][0])
{
fo(j,1,65)
if ((p[i][j]*2%K))
break; if (j>65)
--ans;
}
} printf("%I64d\n",ans/2);
}

C

题意:

给出n*m的方格图,每个格子上有514石头或者为空

从(1,1)开始向(n,m)移动(只能向右/下),每次移动会把一行/一列的石头向右/下推一格,不能把石头推出方格图外

求方案数

题解:

差点就切了的sb题

一个合法的路径有若干次转折,可以发现每次转折时所转到的方向上的石头都没被推过

所以只需要考虑当前方向往后的石头个数即可转移,用前缀和优化

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 1000000007
using namespace std; bool a[2002][2002];
int s1[2002][2002];
int s2[2002][2002];
int f[2002][2002][2];
int g[2002][2002][2];
int n,m,i,j,k,l;
char ch; int main()
{
// freopen("c.in","r",stdin); scanf("%d%d",&n,&m);
fo(i,1,n)
{
fo(j,1,m)
{
ch=getchar();
while (ch!='.' && ch!='R')
ch=getchar(); a[i][j]=ch=='R';
}
} if (a[n][m])
{
printf("0\n");
return 0;
}
if (n==1 && m==1)
{
printf("1\n");
return 0;
} fd(i,n,1)
{
fd(j,m,1)
{
s1[i][j]=s1[i][j+1]+a[i][j];
s2[i][j]=s2[i+1][j]+a[i][j];
}
} f[1][1][0]=1;
f[1][1][1]=1;
fo(i,1,n)
{
fo(j,1,m)
{
if (i>1 || j>1)
{
f[i][j][0]=g[i][j][0];
f[i][j][1]=g[i][j][1];
} fo(k,0,1)
if (f[i][j][k])
{
if (!k)
{
g[i][j][k^1]=(g[i][j][k^1]+f[i][j][k])%mod;
g[i][m-s1[i][j+1]+1][k^1]=(g[i][m-s1[i][j+1]+1][k^1]-f[i][j][k])%mod;
}
else
{
g[i][j][k^1]=(g[i][j][k^1]+f[i][j][k])%mod;
g[n-s2[i+1][j]+1][j][k^1]=(g[n-s2[i+1][j]+1][j][k^1]-f[i][j][k])%mod;
}
} g[i][j+1][1]=(g[i][j+1][1]+g[i][j][1])%mod;
g[i+1][j][0]=(g[i+1][j][0]+g[i][j][0])%mod;
}
} printf("%d\n",((f[n][m][0]+f[n][m][1])%mod+mod)%mod);
}

D

题意:

把一条链进行若干次操作,每次操作选择一个点,把这个点的父亲设为其父亲的父亲

求最小的操作使得能把链变成给出的一棵树,并给出链的初始编号和每次操作的点编号

题解:

很妙的构造题

一开始想把每个点接到兄弟节点中深度最小的点,但是挂了

考虑把树变成链,一次操作实质是把一个点的父亲设为其的一个兄弟节点

由于每次操作树的深度最多+1,所以操作次数的下限为(n-深度)

先找出树上最长链,每次把最长链上的一个点v下移到兄弟u,下移后最长链多了u

每次深度+1,所以这样的操作次数刚好是(n-深度),即为最优

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
using namespace std; int a[100001][2];
int ls[100001];
int fa[100001];
int nx[100001];
int Ans[100001];
bool bz[100001];
int d[100001];
int n,i,j,k,l,len,ans,tot,tot2,mx,mx2,h,t; void New(int x,int y)
{
++len;
a[len][0]=y;
a[len][1]=ls[x];
ls[x]=len;
} void dfs(int t,int d)
{
int i; if (d>mx)
mx=d,mx2=t; for (i=ls[t]; i; i=a[i][1])
fa[a[i][0]]=t,dfs(a[i][0],d+1);
} int main()
{
// freopen("d.in","r",stdin); scanf("%d",&n);
fo(i,2,n)
{
scanf("%d",&fa[i]);++fa[i];
New(fa[i],i);
} dfs(1,1); while (mx2)
{
bz[mx2]=1; nx[fa[mx2]]=mx2;
mx2=fa[mx2];
}
fo(j,1,n)
if (bz[j])
{
for (i=ls[j]; i; i=a[i][1])
if (!bz[a[i][0]])
d[++t]=a[i][0];
} while (h<t)
{
++h;
j=nx[fa[d[h]]]; for (i=ls[d[h]]; i; i=a[i][1])
d[++t]=a[i][0]; fa[j]=d[h];
nx[fa[d[h]]]=d[h];
nx[d[h]]=j; Ans[++tot]=j;
} for (i=1; i; i=nx[i])
printf("%d ",i-1);
printf("\n");
printf("%d\n",tot);
fd(i,tot,1)
printf("%d ",Ans[i]-1);
}

E

题意:

给出一个数k和n个数(都不能整除k),每次可以把两个数合并,合并后的值除k直到不整除为止

求一种把n个数合并成1的方案

n<=16,k<=2000,∑ai<=2000

题解:

O(3^n*2000)的做法显然过不了

可以发现,每种合并的方案最终都可以表示为∑ai*k^bi,其中bi<0

证明每种∑ai*k^bi=1的情况都能对应一种合法方案:

①n=1

那么只有a1=1时才成立

(不存在a1>1的情况)

②n>1

设序列中最小的bi为B,那么必定存在至少两个bi=B

证明:

若只有一个,那么

∑ai*k^bi=1

∑ai*k^(bi-B)=k^(-B)

当bi>B时,乘积必为k的倍数,而右侧也为k的倍数

如果只有一个bi=B,且ai%k≠0,左右在模k意义下不等,实际也必然不等

那么每次把bi=bj=B的ij合并,把新的数的b变为(b+合并后的数除k的次数),合并的数变为f(i+j)即可

可以发现这样仍满足∑ai*k^bi=1,而n-1的所有情况都已经归纳证明了

③n=2

由于n=1比较特殊,所以n=2也要特殊考虑

从n>1的结论得知,b1=b2=B

因为a1*k^B+a2*k^B=1

a1+a2=k^(-B)

所以f(a1+a2)=1,可以变为n=1的情况,即上文所说不存在a1>1


那么dp就很显然了,考虑每次操作加一个a,或者对于所有的a除以k

把一种合法的序列还原时,可以发现其中不存在小数

所以dp时的ai和也必为整数

用bitset优化,反着还原dp,然后正着求出每次操作

还原dp时不需要记录上个状态(因为有bitset),每次枚举一种操作判断原状态是否存在即可

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <bitset>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std; struct type{
int a,b;
} b[17];
int p[17];
int a[17];
int ans[101];
bitset<2001> f[65536];
int n,K,L,i,j,k,l,sum,len,s,tot; bool cmp(type a,type b)
{
return a.b>b.b;
} int main()
{
// freopen("e.in","r",stdin); p[1]=1;
fo(i,2,16)
p[i]=p[i-1]<<1; scanf("%d%d",&n,&K);L=(p[n]<<1)-1;
fo(i,1,n)
scanf("%d",&a[i]),sum+=a[i];
sum/=K; f[0][0]=1;
fo(i,1,L)
{
fo(j,1,n)
if (i&p[j])
f[i]|=f[i^p[j]]<<a[j]; fd(j,sum,1)
if (f[i][j*K])
f[i][j]=1;
} if (!f[L][1])
printf("NO\n");
else
{
printf("YES\n"); s=L;j=1;
while (j)
{
if (j<=sum && f[s][j*K])
{
j*=K;
ans[++len]=-1;
continue;
} fo(i,1,n)
if (s&p[i] && j>=a[i] && f[s-p[i]][j-a[i]])
{
s-=p[i];
j-=a[i];
ans[++len]=i; break;
}
} j=0;
fo(i,1,len)
if (ans[i]==-1)
++j;
else
b[++tot]={a[ans[i]],-j}; while (tot>1)
{
sort(b+1,b+tot+1,cmp); printf("%d %d\n",b[tot-1].a,b[tot].a);
b[tot-1].a+=b[tot].a; --tot;
while (!(b[tot].a%K))
b[tot].a/=K,++b[tot].b;
}
}
}

Codeforces Round #596 Div1 A~E题解的更多相关文章

  1. Codeforces Round #543 Div1题解(并不全)

    Codeforces Round #543 Div1题解 Codeforces A. Diana and Liana 给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下 ...

  2. Codeforces Round #545 Div1 题解

    Codeforces Round #545 Div1 题解 来写题解啦QwQ 本来想上红的,结果没做出D.... A. Skyscrapers CF1137A 题意 给定一个\(n*m\)的网格,每个 ...

  3. Codeforces Round #539 Div1 题解

    Codeforces Round #539 Div1 题解 听说这场很适合上分QwQ 然而太晚了QaQ A. Sasha and a Bit of Relax 翻译 有一个长度为\(n\)的数组,问有 ...

  4. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2)

    A - Forgetting Things 题意:给 \(a,b\) 两个数字的开头数字(1~9),求使得等式 \(a=b-1\) 成立的一组 \(a,b\) ,无解输出-1. 题解:很显然只有 \( ...

  5. # Codeforces Round #529(Div.3)个人题解

    Codeforces Round #529(Div.3)个人题解 前言: 闲来无事补了前天的cf,想着最近刷题有点点怠惰,就直接一场cf一场cf的刷算了,以后的题解也都会以每场的形式写出来 A. Re ...

  6. Codeforces Round #557 (Div. 1) 简要题解

    Codeforces Round #557 (Div. 1) 简要题解 codeforces A. Hide and Seek 枚举起始位置\(a\),如果\(a\)未在序列中出现,则对答案有\(2\ ...

  7. 【Codeforces Round】 #431 (Div. 2) 题解

    Codeforces Round #431 (Div. 2)  A. Odds and Ends time limit per test 1 second memory limit per test ...

  8. Codeforces Round #540 (Div. 3) 部分题解

    Codeforces Round #540 (Div. 3) 题目链接:https://codeforces.com/contest/1118 题目太多啦,解释题意都花很多时间...还有事情要做,就选 ...

  9. Codeforces Round #538 (Div. 2) (A-E题解)

    Codeforces Round #538 (Div. 2) 题目链接:https://codeforces.com/contest/1114 A. Got Any Grapes? 题意: 有三个人, ...

随机推荐

  1. 关于在DBGridEh的一个字段使用checkbox的方法 .

    在DBGridEh的columns中新增加一个字段 1.如果你选择的数据库字段,则选择checkbox为true,并在keylist中输入0和1,就可以了 2.如果你选择的是一个临时字段,在数据集中新 ...

  2. iptables规则

    iptables命令是Linux上常用的防火墙软件,是netfilter项目的一部分 iptables文件设置路径:命令:vim /etc/sysconfig/iptables-config 0x02 ...

  3. DedeCMS调取其他织梦CMS站点数据库数据方法

    第1步:打开网站include\taglib文件夹中找到sql.lib.php文件,并直接复制一些此文件出来,并把复制出来的这个文件重命名为mysql.lib.php.注:mysql.lib.php, ...

  4. finereport点击图表钻取到明细表包括参数传递

    1.  点击编辑图表 2.  参数传递 3.  选择分类名称 4.  钻取明细表获取 inputs 值得方法 使用公司 $inputs   获取钻取传来的值

  5. java保留2位或n位小数

    1.直接使用字符串处理 double ds = Double.valueOf(String.format("%.3f", Math.random()).toString()); 这 ...

  6. kafka 安装教程

    安装详述: https://www.jianshu.com/p/596f107e901a 3.0:运行:cd 到: D:\Installed_software\Professional\kafka_2 ...

  7. Java内存结构详解

    Java内存结构详解 Java把内存分成:栈内存,堆内存,方法区,本地方法区和寄存器等. 下面分别介绍栈内存,堆内存,方法区各自一些特性: 1.栈内存 (1)一些基本类型的变量和对象的引用变量都是在函 ...

  8. kernel编译

    Linux内核编译与安装 Linux内核介绍 Linux内核是一个用C语言写成的,符合POSIX标准的类Unix操作系统.内核是操作系统中最基本的一部分,提供了众多应用程序访问计算机硬件的机制.Lin ...

  9. Redis持久化存储与主从复制

    4. redis持久化 Redis是一种内存型数据库,一旦服务器进程退出,数据库的数据就会丢失,为了解决这个问题,Redis提供了两种持久化的方案,将内存中的数据保存到磁盘中,避免数据的丢失. 4.1 ...

  10. 神经网络之:S型神经元

    1.S 型神经元和感知器类似,但是被修改为权重和偏置的微小改动只引起输出的微小变化 2.S型神经元结构: S型函数: 带有x1,x2,........,权重w1,w2.....,和偏置b的S型神经元的 ...