9.1:
Contest by Dream__Sky
T1:ARC227A 没什么好说的
【其他题&思路暂时被数据删除了(我没保存qwq)】
9.2:
Contest by:梦熊
T1:CF1806B(无多测版)
分类讨论小清新题
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int s,n,a[N];
signed main(){
freopen("arrange.in","r",stdin);
freopen("arrange.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) {
cin>>a[i];
if(a[i]==0) s++;
}
if((!(n%2)&&s<=n/2)||((n&1)&&s<=(n+1)/2)) cout<<0<<'\n';
else{
if(s==n) cout<<1<<'\n';
else{
for(int i=1;i<=n;i++)
if(a[i]>1){
cout<<1<<'\n';
exit(0);
}
cout<<2<<'\n';
}
}
}
T2:CF1780B(无多测版)
也是小清新
对于三个正整数 \(a, b, c\),有 \(gcd(a+b,c) > gcd(a,b,c)\)。
证明也是容易的,设 \(q = gcd(a, b)\),有\(a = q \times m\),\(b = q \times n\) 其中 \(gcd(m,n)=1\)。
相加得
所以得 \(q | (a+b)\),即 \(gcd(a+b,c) > q\) 显然成立。
这个性质说明最优划分一定只会划分为两段,否则将相邻的两段合并起来一定更优。
于是滚一个前缀和,暴力枚举分割点即可,时间复杂度 \(\mathcal{O}(n log V)\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Cosmic{
const int N=1e5+10;
int n,ans,a[N],b[N];
inline void fre(){freopen("partition.in","r",stdin);freopen("partition.out","w",stdout);}
inline void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=b[i-1]+a[i];
}
for(int i=1;i<=n-1;i++) ans=max(ans,__gcd(b[i],b[n]-b[i]));
cout<<ans;
}
}using namespace Cosmic;
signed main(){
fre();
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T=1;
while(T--) solve();
}
T3:CF1303D (无多测版)
(赛时题目是切蛋糕,这里统一也是切蛋糕,原题是放盒子)
首先无解是好判断的,所有蛋糕的和小于 \(n\) 就无解,否则在最坏情况下都可以把蛋糕都切成大小为 \(1\) 然后拼起来。
考虑到 \(n\) 很大,而且 \(a_i\) 有一个 \(2\) 的幂次的限制,不如在二进制下考虑问题。
因为把高位的 \(1\) 往下一位拆会有 \(1\) 的代价,而低位的 \(1\) 向高位的合成是免费的,于是从低位向高位贪
心。
假设现在贪心到了第 \(k\) 位(\(n\) 的二进制表示下第 \(k\) 位为 \(1\)),如果当前存在一块蛋糕大小为 \(2^k\),那么直接用了,剩下的蛋糕向高位合成(两块大小为 \(2^k\) 的蛋糕可以当成一块大小为 \(2^{k+1}\) 的蛋糕),以保证蛋糕的充分利用。
如果不存在,怎么办呢?考虑将大的蛋糕往下面拆,找到最小的一块比 \(2^k\) 大的蛋糕,往下一直切,直到切出一块大小为 \(2^k\) 的蛋糕即可。这样贪心的正确性显然,时间复杂度 \(\mathcal{O}(m+log^2n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Cosmic{
const int N=1e5+10;
int m,count,two[65],b[65],a[N],n,ans;
bool f[65];
inline void fre(){freopen("cake.in","r",stdin);freopen("cake.out","w",stdout);}
inline void solve(){
cin>>m>>n;
count=0;
for(int i=1;i<=n;i++) cin>>a[i],count+=a[i];
int ans1=0,ans2=0;
if(count<m){
cout<<-1;
exit(0);
}
for(int i=1;i<=n;i++){
int x=log(a[i])/log(2);
b[x]++;
}
ans=0;
for(int i=0;i<=62;i++){
if((1ll<<i)&m) f[i]=1;
else f[i]=0;
}
two[0]=b[0];
for(int i=1;i<=62;i++)two[i]=two[i-1]+1ll*((1ll<<i)*b[i]);
int sum=0;
for(int i=0;i<=62;i++){
if(f[i]){
if((1ll<<i)>two[i]-sum){
for(int j=i+1;j<=62;j++)
if(b[j]){
ans+=j-i;
b[j]--,b[i]+=2;
for(int k=i+1;k<j;k++) b[k]++;
break;
}
}
two[0]=b[0];
for(int j=1;j<=62;j++) two[j]=two[j-1]+1ll*((1ll<<j)*b[j]);
sum+=(1ll<<i);
}
}
cout<<ans;
}
}using namespace Cosmic;
signed main(){
fre();
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T=1;
while(T--) solve();
}
T4:
(找不到原题,故在此把题面复制一下)
矩阵(matrix)
题目描述
小 C 有一个大小为 \(n\times m\) 的 01 矩阵 \(A\)。
小 C 认为第 \(i\) 列是好的当且仅当第 \(i\) 列中 1 刚好出现了一次,即 \(\sum_{j=1}^n [A_{j,i}=1]=1\)。
小 C 可以进行以下操作任意次:选择矩阵 \(A\) 中的某一行将其 01 翻转(即 0 变成 1,1 变成 0)。
小 C 想要让矩阵 \(A\) 中好的列数尽可能多,你能告诉他这个最大值吗?
输入格式
第一行输入两个数字 \(n,m\),分别表示矩阵的长与宽。
接下来 \(n\) 行,每行包含一个长度为 \(m\) 仅由 01 组成的字符串。
输出格式
共一行,输出一个整数,表示矩阵 \(A\) 中最多的好的列数。
样例 1 输入
3 4
0101
0110
1011
样例 1 输出
3
样例 1 解释
将每一行都进行翻转,矩阵 \(A\) 变为:
1010
1001
0100
此时第 \(2,3,4\) 列是好的,故答案为 \(3\)。
样例 2 输入
3 3
101
111
000
样例 2 输出
2
其余样例见下发文件。
数据规模与约定
- 对于 \(20\%\) 的数据,保证 \(n,m \le 16\)。
- 对于 \(40\%\) 的数据,保证 \(n,m \le 100\)。
- 对于 \(60\%\) 的数据,保证 \(n,m\le 500\)。
- 对于另 \(20\%\) 的数据,保证 \(n\times m \le 70000\)。
- 对于 \(100\%\) 的数据,保证 \(1\le n,m\le 3\times 10^5\),\(1\le n\times m\le 3\times 10^5\)。
::::
赛时打了个 \(40\) 分的暴力,因为没多少时间了,大概就是直接枚举钦定为 \(1\) 的位置,然后确定所有行的翻转情况并计算答案。
枚举的位置数是 \(\mathcal{O}(nm)\) 的,每次计算答案也是 \(\mathcal{O}(nm)\) 的,总复杂度为 \(\mathcal{O}(n^2 m^2)\)。
//40pts
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Cosmic{
const int N=1000;
int n,m,ans,a[N][N],b[N],cnt[N];
inline void fre(){freopen("matrix.in","r",stdin);freopen("matrix.out","w",stdout);}
inline void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
char ch; cin>>ch;
a[i][j]=ch-'0';
if(a[i][j]==1) cnt[j]++;
}
for(int i=1;i<=m;i++) if(cnt[i]==1) ans++;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(a[i][j]==0){
int p=0;
for(int k=1;k<=m;k++){
if(a[i][k]==0) a[i][k]=1,cnt[k]++;
else a[i][k]=0,cnt[k]--;
}//翻转第i行
if(cnt[j]>1){
for(int k=1;k<=n;k++)
if(a[k][j]==1&&k!=i){
b[++p]=k;
for(int c=1;c<=m;c++){
if(a[k][c]==0) a[k][c]=1,cnt[c]++;
else a[k][c]=0,cnt[c]--;
}
if(cnt[j]==1) break;
}//找到第j个位置是1的行并翻转
}
int sum=0;
for(int k=1;k<=m;k++) if(cnt[k]==1) sum++;
// cout<<i<<' '<<j<<' '<<sum<<'\n';
ans=max(ans,sum);
for(int k=1;k<=m;k++){
if(a[i][k]==0) a[i][k]=1,cnt[k]++;
else a[i][k]=0,cnt[k]--;
}
for(int k=1;k<=p;k++)
for(int c=1;c<=m;c++){
if(a[b[k]][c]==0) a[b[k]][c]=1,cnt[c]++;
else a[b[k]][c]=0,cnt[c]--;
}//复原
// for(int i=1;i<=m;i++) cout<<cnt[i]<<' ';
}
}
cout<<ans;
}
}using namespace Cosmic;
signed main(){
fre();
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T=1;
while(T--) solve();
}
正解肥肠纽币。考虑到 \(1\le n\times m\le 3\times 10^5\)。所以正解肯定要从 \(n \times m\) 下手。
考虑如果 \((i, j)\) 和 \((k, l)\) 两个位置 \((j \neq l)\) 能够同时为 \(1\),那么两个位置所对应的行的翻转情况一定是一样的!
于是考虑对每个位置所对应的行的翻转情况进行 hash,一种行的翻转情况对应 hash 值计算方式如下:\(\sum^n_{i=1}C_ip^i\),其中 \(C_i\) 表示第 \(i\) 行是否翻转,\(p\) 为任意取的一个大质数。将所有的 \(hash\) 值丢进一个 \(map\) 里,相同值个数最多的就是答案。
时间复杂度 \(\mathcal{O}(nm)\)。
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
namespace Cosmic{
const int N=3e5+10,mod=911;
inline void fre(){freopen("matrix.in","r",stdin);freopen("matrix.out","w",stdout);}
int n,m,pw[N],_[N],__[N];
map<int,int> cnt;
vector<int> a[N];
inline void init(){
pw[0]=1;
for(int i=1;i<=N;i++) pw[i]=pw[i-1]*mod;
}
inline void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++){
a[i].push_back(0);
for(int j=1;j<=m;j++){
char ch; cin>>ch;
a[i].push_back(ch-'0');
}
}
int mx=0;
for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++) _[i]=_[i-1]+a[i][j]*pw[i];
__[n+1]=0;
for(int i=n;i>=1;i--) __[i]=__[i+1]+a[i][j]*pw[i];
for(int i=1;i<=n;i++){
int val=_[i-1]+__[i+1]+(1-a[i][j])*pw[i];
cnt[val]++;
if(cnt[val]>mx) mx=cnt[val];
}
}
cout<<mx;
}
}using namespace Cosmic;
signed main(){
init();
fre();
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T=1;
while(T--) solve();
}
9.3
T1:CF1732A(无多测版)
手玩发现答案总 \(\le 3\),分类讨论即可
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Cosmic{
inline void fre(){freopen("unite.in","r",stdin);freopen("unite.out","w",stdout);}
const int N=1e5+10;
int n,a[N],s;
inline void solve(){
cin>>n;
for(int i=1;i<=n;i++) {
cin>>a[i];
if(i==1) s=a[i];
else s=__gcd(s,a[i]);
}
if(s==1){
cout<<0;
exit(0);
}
if(n==1){
if(a[1]==1) cout<<0<<'\n';
else cout<<1<<'\n';
exit(0);
}
if(n==2){
if (__gcd(a[1],a[2])==1) cout<<0<<'\n';
else if (__gcd(a[1],__gcd(a[2],2ll))==1) cout<<1<<'\n';
else cout<<2<<'\n';
exit(0);
}
int gcd=0;
for (int i=1;i<=n-2;i++) gcd=__gcd(a[i],gcd);
if (__gcd(gcd,__gcd(a[n],a[n-1]))==1) cout<<0<<'\n';
else if (__gcd(gcd,__gcd(__gcd(a[n],n),a[n-1]))==1) cout<<1<<'\n';
else if (__gcd(gcd,__gcd(a[n],__gcd(a[n-1],n-1)))==1) cout<<2<<'\n';
else cout<<3<<'\n';
}
}using namespace Cosmic;
signed main(){
fre();
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T=1;
while(T--) solve();
}
T2:CF902B
赛时打了个 dfs,赛后一看,RE 了,结果发现正解是如果当前结点 \(u\) 和自己的父亲结点 \(p_u\) 颜色不一样,操作次数就加一。。。无语了。
#include<bits/stdc++.h>
//#define int long long
using namespace std;
namespace Cosmic{
inline void fre(){freopen("color.in","r",stdin);freopen("color.out","w",stdout);}
const int N=1e5+10;
int n,fa[N],c[N],ans;
inline void solve(){
cin>>n;
for(int i=2;i<=n;i++) cin>>fa[i];
for(int i=1;i<=n;i++) cin>>c[i];
for(int i=1;i<=n;i++) if(c[i]!=c[fa[i]]) ans++;
cout<<ans;
}
}using namespace Cosmic;
signed main(){
fre();
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T=1;
while(T--) solve();
}
T3:CF1822G2(无多测版)
最简单的就是 \(\mathcal{O}(n^3)\) 的暴力(赛时机房里有人此题保龄,被ll训了)。
然后看到有 \(a_i \le 5 \times 10^3\) 和 \(a_i \le 10^6\) 的部分分。考虑优化,使复杂度带一个值域。
考虑枚举 \(a_i\),对于任意一个满足条件的正整数 \(b\) 的大小一定是 \(\le \sqrt{V}\) 的(这里 \(V\) 表示值域)
然后判断 \(a_i \times b\) 和 \(a_i \times b^2\) 有没有即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Cosmic{
inline void fre(){freopen("triple.in","r",stdin);freopen("triple.out","w",stdout);}
const int N=1e5+10;
int n,a[N],mx,ans;
map<int,int> mp;
inline void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
mx=max(mx,a[i]);
mp[a[i]]++;
}
stable_sort(a+1,a+n+1);
int m=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=m;i++) ans+=mp[a[i]]*(mp[a[i]]-1)*(mp[a[i]]-2);
for(int i=1;i<=m;i++)
for(int b=2;a[i]*b*b<=mx;b++){
int x=a[i],y=a[i]*b,z=a[i]*b*b;
if(mp[x]&&mp[y]&&mp[z]) ans+=mp[x]*mp[y]*mp[z];
}
cout<<ans;
}
}using namespace Cosmic;
signed main(){
fre();
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T=1;
while(T--) solve();
}
但是这个代码有一些特例的点是卡不过去的,正解是根号分治,复杂度为 \(\mathcal{O}(nV^{\frac{1}{3}})\)。
但但但但但是,我们动用人类智慧。使用手写 hash 或者是在代码前面加一个火车头,就卡过去了。本人在网上随便找了篇火车头优化,加在上面的代码就卡过去了(9.3日 13:45 时发现只要机子没被宇宙射线攻击,\(\mathcal{O}(n\sqrt{V})\)也能过,最大点的时间为 \(1.5s\))。
T4:CF1827B2
题目大意就是:
有一个元素两两不同的长度为 \(n\) 的序列 \(A\),但是这个序列可能是无序的。
设 \(f_{l,r}\) 表示在只考虑序列 \(A\) 的区间 \([l,r]\) 的前提下,让子序列 \([A_l,A_{l+1},...,A_r]\) 有序的最小代价和。
求
的值。
每次操作完后加代价算感觉很神秘不会码,考虑算出对所有的子序列都做一遍操作的总代价以后,减去多余操作的部分。
注意到问题本质转化为了有多少个三元组 \((i, j, k)(i \le j < k)\) 满足区间 \([i, j]\) 的最大值小于 \([j+1, k]\) 的最小值。
不如考虑枚举区间 \([i, j]\) 的最大值 \(x\),可以通过 set 找到前一个比 \(x\) 大的数的位置 \(a\),后一个比 \(x\) 大的数的位置 \(c\),\(c\) 后面第一个比 \(x\) 小的数的位置 \(d\)。
那么 \(i\) 可以在 \((a, b]\) 中选,\(j\) 一定是 \(c-1\),\(k\) 可以在 \([c,d]\) 中选,贡献为 \((b-a) \times (d-c)\)。
时间复杂度 \(\mathcal{O}(n log n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Cosmic{
inline void fre(){freopen("sort.in","r",stdin);freopen("sort.out","w",stdout);}
const int N=3e5+10;
int n,a[N],ans,pos[N];
set<int> _,__;
inline bool cmp(int x,int y){
return a[x]<a[y];
}
inline void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) ans=ans+(i-1)*(n-i+1);
// cout<<ans<<'\n';
for(int i=0;i<=n+1;i++) _.insert(i);
__.insert(0); __.insert(n+1);
for(int i=1;i<=n;i++)pos[i]=i;
sort(pos+1,pos+n+1,cmp);
// for(int i=1;i<=n;i++) cout<<pos[i]<<' ';
// putchar('\n');
for(int i=1;i<=n;i++){
int y=pos[i];
int x=*(--_.lower_bound(y)),z=*_.upper_bound(y);
if(z!=n+1){
int cw=*__.upper_bound(z);
ans-=(y-x)*(cw-z);
}
_.erase(y); __.insert(y);
}
cout<<ans;
}
}using namespace Cosmic;
signed main(){
fre();
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T=1;
while(T--) solve();
}
浙公网安备 33010602011771号