NOIP模拟1

赛时rank3,95,30,40,5,5

赛后hack,rank7,40,30,40,5,5

CAI

T1 分糖果

简要题意:
n个数分成最多组,使得每组有3个人,每组的数字和能被3整除,输出组数和方案

n105,1ai105

solution:

将每个数mod3存入,则有三类:余数为0,1,2;

可以的方案有三种0,0,00,1,21,1,12,2,2

考虑到0,1,2不少于三个时无意义,所以枚举0,1,2的个数,时间复杂度O(n)

code:

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
const int N = 1e5 + 10;
int n,a[N];
queue<int> tot[3];
signed main(){
#ifndef ONLINE_JUDGE
infile("in.in");outfile("out.out");
#else
#endif
cin.tie(0)->sync_with_stdio(false);
cout.tie(0)->sync_with_stdio(false);
cin>>n;
for(int i = 1;i <= n; ++i) cin>>a[i];
for(int i = 1;i <= n; ++i) tot[a[i]%3].push(i);
int emm = min({tot[0].size(),tot[1].size(),tot[2].size()});
ll ans = 0,res = 0;
for(int i = 0;i <= min(emm,2); ++i){
if(ans < (tot[0].size()-i)/3+(tot[1].size()-i)/3+(tot[2].size()-i)/3+i){
ans = (tot[0].size()-i)/3+(tot[1].size()-i)/3+(tot[2].size()-i)/3+i;
res = i;
}
}
cout<<ans<<'\n';
if(!ans) return 0;
while(res--){
cout<<tot[0].front()<<' '<<tot[1].front()<<' '<<tot[2].front()<<'\n';
tot[0].pop();tot[1].pop();tot[2].pop();
}
while(tot[0].size()>=3){
cout<<tot[0].front()<<' ';tot[0].pop();
cout<<tot[0].front()<<' ';tot[0].pop();
cout<<tot[0].front()<<'\n';tot[0].pop();
}
while(tot[1].size()>=3){
cout<<tot[1].front()<<' ';tot[1].pop();
cout<<tot[1].front()<<' ';tot[1].pop();
cout<<tot[1].front()<<'\n';tot[1].pop();
}
while(tot[2].size()>=3){
cout<<tot[2].front()<<' ';tot[2].pop();
cout<<tot[2].front()<<' ';tot[2].pop();
cout<<tot[2].front()<<'\n';tot[2].pop();
}
}

T2 乒乓球

找循环节,不会打,待填

T3 与或

简要题意:

给定一个长度为n的数组a(n105),和k|运算符,nk1&运算符,用以上n1个符号将数组连接起来,从左到右计算结果,使得结果最大并且符号序列的字典序最小,输出结果和符号序列。

样例输入1

4 2
1 3 5 7

样例输出1

7
||&

样例输入2

4 1
1 3 5 7

样例输出2

7
&&|

solution:

有一个结论:&放在|前一定不劣。

证明:假设有三个相邻的位置x,y,z,左边是,右边是&,那么结果最大是z,假设左边是&,右边是,那么结果最小是z

考虑按位贪心,对于当前位置,若放了|后后续最大答案仍是理论最大值,则放|,反之,则放&

code:

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
const int N = 2e5 + 10;
int n,k,sum[N][61];
ll a[N];
inline ll check(int pos,ll val,int k){
if(pos <= n - k){
vector<int> t(60);
for(int i = 0;i < 60; ++i)
t[i] = sum[n-k][i] - sum[pos-1][i];
for(int i = 0;i < 60; ++i)
if(t[i] != (n-k-pos+1) && ((val>>i)&1))
val ^= (1ll<<i);
}
if(k >= 1){
vector<int> t(60);
for(int i = 0;i < 60; ++i) t[i] = sum[n][i] - sum[n - k][i];
for(int i = 0;i < 60; ++i) if(t[i]) val |= (1ll<<i);
}
return val;
}
signed main(){
#ifdef ONLINE_JUDGE
infile("in.in");outfile("out.out");
#else
#endif
cin.tie(0)->sync_with_stdio(false);
cout.tie(0)->sync_with_stdio(false);
cin>>n>>k;
for(int i = 1;i <= n; ++i) cin >> a[i];
for(int i = 1;i <= n; ++i){
for(int j = 0;j < 60; ++j) sum[i][j] = sum[i-1][j];
for(int j = 0;j < 60; ++j) sum[i][j] += ((a[i]>>j)&1);
}
ll mx = check(2,a[1],k);
cout<<mx<<'\n';
int nowk = k;ll ans = 1;
for(int i = 2;i <= n; ++i){
if(nowk >= 1 && check(i+1,ans|a[i],nowk-1) == mx){
cout<<'|';
ans |= a[i];
nowk--;
}
else cout<<'&',ans &= a[i];
}
}

T4 跳舞

solution:

oki,j表示ij可以消去,利用区间dp

oki,j=maxoki,k1&okk+1,j&[gcd(a[i1],a[k])>1||gcd(a[k],a[j+1])>1]

再考虑设fi表示钦定留下第i个,可以删掉几个人

则有

fi=maxfj+((ij1)&okj+1,i1)

注意处理ok的边界,oki,i1=1

code:

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
const int N = 510;
bitset<N> ok[N];
int n,a[N],f[N];
bitset<N> gcd[N];
signed main(){
#ifndef ONLINE_JUDGE
infile("in.in");outfile("out.out");
#else
#endif
cin.tie(0)->sync_with_stdio(false);
cout.tie(0)->sync_with_stdio(false);
cin >> n;
for(int i = 1;i <= n; ++i) cin >> a[i];
for(int i = 1;i <= n; ++i)
for(int j = 1;j <= n; ++j)
gcd[i][j] = (__gcd(a[i],a[j])>1);
for(int i = 1;i <= n; ++i)
if(gcd[i][i-1] || gcd[i][i+1]) ok[i][i] = true;
for(int i = 1;i <= n; ++i){
for(int j = 1;j < i; ++j){
ok[i][j] = true;
}
}
for(int len = 2;len <= n; ++len){
for(int i = 1;i + len - 1 <= n; ++i){
int ed = i + len - 1;
for(int j = i;j <= ed; ++j){
if(ok[i][ed]) break;
ok[i][ed] = (ok[i][j-1]&&ok[j+1][ed]&&(gcd[j][i-1]||gcd[j][ed+1]));
}
}
}
for(int i = 2;i <= n+1; ++i){
for(int j = 0; j < i; ++j){
f[i] = max(f[i],f[j]+(i-j-1)*ok[j+1][i-1]);
}
}
cout<<f[n+1];
}

T5 音乐播放器

概率dp,不会……,待填

总结:
还是

CAI

posted @   CuFeO4  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示