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
知识点:构造、贪心
注意到题目要求字符串长度不超过
,而
大概是三万多不到4万,所以可以在8万以内完成构造。
一种简单的构造方式是这样:找到一个数
,求出
的商
和余数
,那么则有
。所以先用
个左括号,再用
个右括号,构成的字符串有
个括号对。之后在第
个左括号的后面插入一个右括号,就正好增加了
个括号对,符合题目要求。
大概长这个样子:
(((....((()((((...((())))....)))))
注意要特判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
知识点:构造、数学
观察到
不超过
的一半,那么就简单了。
由于不大于
的所有正整数***有
个偶数(向下取整),那么如果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
要注意特判
的情况,因为n=5,k=2的时候无法在6后面接一个3了(不存在正整数6),所以无解。
ps:如果
的时候怎么构造?
#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而言,最大的贡献是
(后面无法找到有
个2的贡献)。
对于大于2的素数p而言,最大的贡献是
(后面无法找到有
个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,那么总方案数就是
每次操作有可能增加或减少连通块的数量,并改变连通块的大小,用并查集维护即可。
#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的十位数是奇数还是偶数。因为
,而2、3、7、8的幂的个位数是4个一循环,所以只用观察a模4是2还是0就行。
如果a的个位数是其他的,那么可以直接输出答案:a的个位数是0 1 5 6 9输出本身即可。a个位数是4则输出6。
当n大于2时,由于
,而如果a是偶数,
模4的值是确定的,所以
的个位数也是确定的。而如果a是奇数(特指个位数是3和7),那么
模4取决于
模4的值。如果
模4为1,那么
模4也是1,此时a的个位数是3和7的话,
的个位数也是3和7,否则应为7和3。
a的个位数是{0,1,2,3,4,5,6,7,8,9}时,对应的
的个位数为{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<