题目链接:https://ac.nowcoder.com/acm/contest/9854
2020已经过去了,希望他能够带走我的拖延症和健忘症呀!嘿嘿,今天是2021新年的第一天,努力,奋斗!
给出了15个多选题,每行输出答案即可
错了好几次直接劝退了,呜呜呜,事实证明,度娘不靠谱了, 代码是赛后看的,也算是补充了点文化常识吧
#include
using namespace std;
#define ll long long
int main()
{
cout<<"D"<
给两个序列ab,相当于构造一个序列c,其中c[i]要么是a[i],要么是a[i]+b[i],要么是a[i]-b[i],现在要求c的总和对y取模的最大值
算是一个较基础的dp吧,思想跟01背包差不多,dp[i][j]做标记用,表示对于c数组从1到i求和取模存不存在j,最后只需要在dp[n][j]当中找到最大的j使得dp[n][j]=1即可
dp[i - 1][(j - d1 + y) % y]表示如果当前c[i]取a[i],那么为了得到j,那么就得看1到i-1求和能不能得到j-d1了,剩下两个同理。
#include
using namespace std;
#define ll long long
#define lowbit(x) x&(-x)
const int N = 1e5 + 5;
const int M = 105;
int dp[N][M], a[N], b[N];
int main(){
int n, y;
scanf("%d%d",&n, &y);
for(int i = 1; i <= n; i ++) scanf("%d",&a[i]);
for(int i = 1; i <= n; i ++) scanf("%d",&b[i]);
for(int i = 1; i <= n; i ++){
int d1, d2, d3; // c数组的三种情况
d1 = a[i] % y;
d2 = (a[i] - b[i] + y) % y;
d3 = (a[i] + b[i]) % y;
dp[i][d1] = dp[i][d2] = dp[i][d3] = 1;
for(int j = 0; j < y; j ++){
if(dp[i - 1][(j - d1 + y) % y] || dp[i - 1][(j - d2 + y) % y] || dp[i - 1][(j - d3 + y) % y])
dp[i][j] = 1;
}
}
int d = y - 1; //取模最大值是y-1
while(!dp[n][d]) d --;
printf("%d", d);
return 0;
}
给你n个数,求最小的数t,使得t跟这n个数都互质。
首先如果n个数中没有1那么1跟他们都互质,所以直接输出1好了。
我是先筛出所有质因子,然后拿这些质因子标记所有他们的倍数,这些数都不能选,因为都不互质的,然后差不多就是前缀和加二分找mex的思想找答案
后来发现是我想太复杂了,可以直接边筛素数边找答案的,学到了~
质因子分解+前缀和+二分
#include
using namespace std;
#define ll long long
#define lowbit(x) x&(-x)
const int maxn = 1e5 + 5;
int vis[maxn], sum[maxn];
int main(){
int t, x;
map mp;
scanf("%d",&t);
while(t --){
scanf("%d",&x);
mp[x] ++;
}
if(mp.begin()->first != 1) {
puts("1");
return 0;
}
vis[1] = 1;
set s; //存质因子
for(auto it : mp){ //遍历mp
int d = it.first;
if(d == 1) continue;
for(int i = 2; i * i <= d; i ++){
if(d % i == 0) {
while(d % i == 0) d /= i;
s.insert(i);
}
}
if(d > 1) s.insert(d);
}
for(auto it : s){
int tmp = it;
while(tmp < maxn){//标记质因子的倍数
vis[tmp] = 1;
tmp += it;
}
}
for(int i = 1; i < maxn; i ++) {
sum[i] = sum[i - 1] + vis[i];//求前缀和
}
int l = 1, r = maxn, ans = -1;
while(l <= r){
int mid = l + r >> 1;
if(sum[mid] < mid) ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%d",ans);
return 0;
}
边质数筛边找答案
#include
using namespace std;
#define ll long long
const int maxn = 1e5 + 5;
int vis[maxn];
int prime[maxn];
int work(){
if(vis[1] == 0) return 1;
for(int i = 2; i < maxn; i ++){
int flag = 0;
if(prime[i]) continue;
for(int j = 1; j * i < maxn; j ++){
prime[i * j] ++;
if(vis[i * j]) flag = 1;
}
if(!flag) return i;
}
return -1;
}
int main(){
int n; scanf("%d",&n);
for(int i = 1; i <= n; i ++) {
int x; scanf("%d",&x);
vis[x] = 1;
}
printf("%d", work());
return 0;
}
有三种蛇,现在来构造衔尾蛇, 可以选不超过n条蛇,让他们首尾连接形成环,问可以构造多少种环
蛇的数量不大才12,可直接进制枚举,三进制表示三个状态,再判断是否合法即可
#include
using namespace std;
#define ll long long
set s;
int main(){
int a, b, c, n, sum = 1;
scanf("%d%d%d",&a, &b, &c);
n = a + b + c;
for(int j = 1; j <= n; j ++){ //枚举蛇的数量
sum *= 3;
for(int i = 0; i < sum; i ++){ //状态枚举
int p = i, ca = 0, cb = 0, cc = 0;
string tmp = "";
for(int k = 0; k < j; k ++){ //该状态下选的蛇, tmp是构成的环
if(p % 3 == 0) tmp += "a", ca ++;
if(p % 3 == 1) tmp += "b", cb ++;
if(p % 3 == 2) tmp += "c", cc ++;
p /= 3;
}
if(ca > a || cb > b || cc > c) continue; //判断该状态选的蛇是否合法
string ans = tmp + tmp; //由于是环形那么就加一层,然后滑动窗口一样取长度是j的那么就是环的所有情况了
int flag = 0;
for(int k = 0; k < j; k ++) {
if(s.count(ans.substr(k, j))){ //判断之前是否存在过
flag = 1;
break;
}
}
if(!flag) s.insert(tmp); //不存在,那么记录答案
}
}
printf("%d\n", s.size());
return 0;
}
有一个函数F(x)表示x是奇数是,那么F(x)=F(x+1)+1,否则F(x)=F(x/2)+1
现在给你一个F(x)的值,让你输出任意一个x,如果不存在则输出-1
暴力跑状态,发现函数值最大也就120。
a[i]表示F(x)=i的那个x值,也就是说F(a[i]) = i。
我是这么构造的,其实就是反函数的思想,函数的逆过程:
前几个可以初始化a[1]=1,a[2]=2,a[3]=3
如果a[i-1]是奇数时,那么a[i]应该是a[i-1]乘2了,比如说F(3)是4,3的下一个状态是F(6)是由3得到的, 那么F(6) 是5,在这里反推就是a[4]=3,a[5] = a[4] * 2 = 6
如果a[i-1]是偶数时,那么a[i]应该是a[i-1]减1了,比如说F(4)是3,那么下一个状态F(3)是由4得到的,那么F(3)是4,在这里反推就是a[3]=4, a[4] = a[3] - 1 = 3
当a[i]大于1e18的时候可以退出。
#include
using namespace std;
#define ll long long
const int maxn = 200;
ll a[maxn];
int main(){
int t, i; scanf("%d", &t);
a[1] = 1; a[2] = 2; a[3] = 4;
for(i = 4;; i ++){
if(a[i - 1] & 1) a[i] = a[i - 1] * 2;
else a[i] = a[i - 1] - 1;
if(a[i] > 1e18) break;
}
while(t--){
ll n; scanf("%lld",&n);
if(n >= i) puts("-1");
else printf("%lld\n", a[n]);
}
return 0;
}