明显感觉到码力下降了 需要老年人康复训练计划
这场码力比较大 需要思维比较巧来减少码力 算是少见的cf div2了
A. Anti-knapsack
给你
n
n
n 和
k
k
k ,问是否有办法找出最大的集合使得集合中任意子集和不为k 我们发现每次分奇偶去掉
m
/
2
m/2
m/2 (分奇偶),那么也意味着
i
<
=
m
/
2
i <= m/2
i<=m/2 (分奇偶)也凑不出来 毕竟按照我们的定义可以无限递归下去 这样我们凑
m
=
11
m = 11
m=11 的时候,
11
=
1
+
3
+
7
11 = 1 + 3 + 7
11=1+3+7
11
=
4
+
7
11 = 4 + 7
11=4+7 那么按照我们的规则
4
4
4 是凑不出来的 因为没有
1
、
2
、
3
、
4
1、2、3、4
1、2、3、4 所以我们只用考虑
11
=
4
+
7
11 = 4 + 7
11=4+7 不需要考虑递归下去的情况
#include<cstdio>
using namespace std;
const int MAX_N = 1025;
int arr[MAX_N];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
int cnt = 0;
scanf("%d%d",&n,&m);
if(m%2==0)
{
for(int i = m/2;i<=n;++i)
{
if(i==m) continue;
arr[++cnt] = i;
}
}
else
{
for(int i = m/2+1;i<=n;++i)
{
if(i==m) continue;
arr[++cnt] = i;
}
}
printf("%d\n",cnt);
for(int i = 1;i<=cnt;++i)
{
i==cnt?printf("%d\n",arr[i]):printf("%d ",arr[i]);
}
}
return 0;
}
B. Planet Lapituletti
比较烦躁的模拟 给你一个镜面数字 并且给你
n
n
n 小时制 与
m
m
m 分钟制度 问你能不能找一个给出时间的将来时刻(包括给出时间)满足时间为镜面时间 按照镜面时间的定义去搜索 符合条件的则输出 否则到下一天认为是 00:00
#include<cstdio>
#include<map>
#include<iostream>
using namespace std;
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
#define dbg3(x,y,z) cout << #x << " = " << (x) << " " << #y << " = " << (y) << " " << #z << " = " << (z) << endl;
char str[15];
map<int,int> mp;
int arr[6] = {0,0,1,2,5,8};
int main()
{
int t,n,m;
scanf("%d",&t);
mp[0] = 0;
mp[1] = 1;
mp[2] = 5;
mp[5] = 2;
mp[8] = 8;
while(t--)
{
int ans_h = -1,ans_mi = -1;
scanf("%d%d",&n,&m);
scanf("%s",str+1);
bool flag = false;
int h = (str[1]-'0')*10 + str[2]-'0';
int mi = (str[4]-'0')*10 + str[5] - '0';
int minn = 0x3f3f3f3f;
for(int i = 1;i<=5;++i)
{
for(int j = 1;j<=5;++j)
{
int h_ = arr[i]*10+arr[j];
if(h_>=n||h_<h) continue;
for(int k = 1;k<=5;++k)
{
for(int l = 1;l<=5;++l)
{
int mi_ = arr[k]*10+arr[l];
if(mi_>=m||(h_==h&&mi_<mi)) continue;
if((mp[arr[l]]*10+mp[arr[k]]>=n)||(mp[arr[j]]*10+mp[arr[i]]>=m)) continue;
if(((h_-h)*m+mi_-mi)<minn)
{
minn = ((h_-h)*m+mi_-mi);
ans_h = h_;
ans_mi = mi_;
flag = true;
}
}
}
}
}
if(flag)
{
if(ans_h<10) printf("0");
printf("%d:",ans_h);
if(ans_mi<10) printf("0");
printf("%d\n",ans_mi);
}
else printf("00:00\n");
}
return 0;
}
C. K-beautiful Strings
题意:给你
n
n
n 长度的字符串,与
k
k
k 问你能不能找到一种字典序大于小于给出字符串的字符串满足每个字母出现次数的和为
k
k
k 的倍数
做法:如果字符串本身满足 我们输出字符串 否则一定需要增大字典序 我们发现如果去倒着遍历求一遍第一个增大字典序的位置 这样怎么check 是否合理是关键,因为是倒着枚举 我们能填放的位置均在后面为
n
−
x
b
n-xb
n−xb
x
b
xb
xb 为枚举的下标 我们只要用这个判断出现了几个字母 * k 是否大于
n
−
x
b
n-xb
n−xb 进行check 找到第一个符合的按照字典序从大到小从后面往前插入,因为此时字典序已经比原字符串大 你可以放完再sort逻辑也是一致的
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
#include<cstring>
#include<set>
#include<cmath>
#include<stack>
using namespace std;
const int MAX_N = 100025;
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
#define dbg3(x,y,z) cout << #x << " = " << (x) << " " << #y << " = " << (y) << " " << #z << " = " << (z) << endl;
char str[MAX_N],ans[MAX_N];
int n,m,sum[MAX_N][29],tmp[29];
bool check(int xb,int ckStr)
{
int cnt = 0;
for(int i = 0;i<26;++i) tmp[i] = sum[xb-1][i];
tmp[ckStr]++;
for(int i = 0;i<26;++i)
{
if((tmp[i]%m)!=0)
{
tmp[i] = m-(tmp[i]%m),cnt+=tmp[i];
}
else
{
tmp[i] = 0;
}
}
if(cnt>n-xb) return false;
for(int i = 1;i<=n;++i) ans[i] = str[i]; // important
ans[xb] = 'a' + ckStr;
for(int i = n;i>xb;--i)
{
for(int j = 25;j>=0;--j)
{
if(tmp[j])
{
ans[i] = 'a' + j;
tmp[j]--;
goto thisEnd;
}
}
ans[i] = 'a';
thisEnd:;
}
ans[n+1] = '\0';
printf("%s\n",ans+1);
return true;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
scanf("%s",str+1);
if(n%m)
{
printf("-1\n");
continue;
}
for(int i = 1;i<=n;++i)
{
for(int j = 0;j<26;++j)
{
sum[i][j] = sum[i-1][j];
}
sum[i][str[i]-'a'] = sum[i-1][str[i]-'a'] + 1;
}
bool flag = true;
for(int i = 0;i<26;++i)
{
if((sum[n][i]%m)!=0) flag = false;
}
if(flag)
{
printf("%s\n",str+1);
continue;
}
for(int i = n;i>=1;--i)
{
for(int j = str[i]-'a' + 1;j<26;++j)
{
if(check(i,j)) goto haveEnd;
}
}
printf("-1\n");
haveEnd:;
}
return 0;
}
D. GCD of an Array
给你
n
n
n 个数字,
m
m
m 个操作
操作是将第
i
i
i 位乘上
x
x
x
问你所有的数当前GCD为多少
一开始直接撸了个线段树,但是 gcd(A,B)%MOD != gcd(A%MOD,B%MOD) 就会
W
A
WA
WA
后续是要对质因数进行处理,用一个 multiset 去存储每个质因数存放的下标,如果下标的
s
i
z
e
size
size 到了
n
n
n 我们认为是产生贡献 如此我们用一个
m
p
mp
mp 存储每个质因数当前的贡献 例如是几次方 模拟即可 一开始用
s
e
t
set
set 去维护每次访问到的不同质因子 会
T
L
E
TLE
TLE 用数组减少常数过了
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
#include<cstring>
#include<set>
#include<cmath>
#include<stack>
using namespace std;
const int MAX_N = 200025;
const int MOD = 1000000007;
multiset<int> st[MAX_N];
map<int,int> mp[MAX_N];
#define ll long long
#define dbg(x) cout << #x << " = " << (x) << endl;
#define dbg2(x,y) cout << #x << " = " << (x) << " " << #y << " = " << (y) << endl;
#define dbg3(x,y,z) cout << #x << " = " << (x) << " " << #y << " = " << (y) << " " << #z << " = " << (z) << endl;
int nxt[MAX_N],n,stTmp[MAX_N],brr[MAX_N];
ll ans;
void init()
{
nxt[1] = 1;
for(int i = 2;i<MAX_N;++i)
{
if(nxt[i]==0)
{
nxt[i] = i;
if(i>10000) continue; // 怕爆long long
for(int j = i*i;j<MAX_N;j+=i)
{
if(nxt[j]==0) nxt[j] = i;
}
}
}
}
void add(int xb,int x)
{
int xbNow = 0;
while(nxt[x]!=1)
{
if(!xbNow||stTmp[xbNow]!=nxt[x])
{
stTmp[++xbNow] = nxt[x];
if(mp[xb].find(nxt[x])!=mp[xb].end()) brr[xbNow] = mp[xb][nxt[x]];
else brr[xbNow] = 0,mp[xb][nxt[x]] = 0;
}
mp[xb][nxt[x]]++;
x /= nxt[x];
}
for(int i = 1;i<=xbNow;++i)
{
int minn=1,minnNow=0;
if(!brr[i]) st[stTmp[i]].insert(brr[i]);
if(st[stTmp[i]].size()==n)
{
minn = *st[stTmp[i]].begin();
}
st[stTmp[i]].erase(st[stTmp[i]].find(brr[i]));
st[stTmp[i]].insert(mp[xb][stTmp[i]]);
if(st[stTmp[i]].size()==n)
{
minnNow = *st[stTmp[i]].begin();
}
for(int j = minn+1;j<=minnNow;++j)
{
ans = ans * stTmp[i] % MOD;
}
}
}
int main()
{
init();
int m,xb,x;
ans = 1;
scanf("%d%d",&n,&m);
for(int i = 1;i<=n;++i)
{
scanf("%d",&x);
add(i,x);
}
while(m--)
{
scanf("%d%d",&xb,&x);
add(xb,x);
printf("%lld\n",ans);
}
return 0;
}