A
对数组排序,如果存在相邻两项为1,则最少可以分成两组,否则分成1组。
#include<bits/stdc++.h>
using namespace std;
int a[200];
int main(){
int T;
cin>>T;
while(T--){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
int res=0;
for(int i=2;i<=n;i++){
if(a[i]-a[i-1]==1) res++;
}
if(res) cout<<2<<endl;
else cout<<1<<endl;
}
return 0;
}
B1&B2
整个问题可以转化为一个图求各个环的大小的问题,由于每个点只会在一个环中出现,考虑
D
S
U
DSU
DSU 或
T
a
r
j
a
n
Tarjan
Tarjan 求环即可。
时间复杂度
O
(
n
)
O(n)
O(n)。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+100;
vector<int> G[N];
bool is_instack[N];
int dfn[N],low[N],siz[N],color[N],a[N];
stack<int> sta;
int n,m,idx,scc;
void init(int n){
idx=scc=0;
for(int i=0;i<=n;i++) dfn[i]=low[i]=is_instack[i]=color[i]=siz[i]=0;
while(!sta.empty()) sta.pop();
for(int i=0;i<=n;i++) G[i].clear();
}
void Tarjan(int u){
low[u]=dfn[u]=++idx;
is_instack[u]=1;sta.push(u);
for(int v:G[u]){
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(is_instack[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
scc++;
while(1){
int temp=sta.top();
color[temp]=scc;
siz[scc]++;
is_instack[temp]=0;
sta.pop();
if(temp==u) break;
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init(n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
G[i].push_back(a[i]);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) Tarjan(i);
}
for(int i=1;i<=n;i++){
printf("%d ",siz[color[i]]);
}
puts("");
}
return 0;
}
C1&C2
g o o d n u m b e r good number goodnumber的本质即为三进制下各位都不是 2 2 2的数字,因此对于 n n n,在三进制下找到 2 2 2最左边的 0 0 0然后变为 1 1 1,后面的全部变为 0 0 0即可。复杂度 O ( T ∗ l o g 3 ( n ) ) O(T*log_3(n)) O(T∗log3(n))。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string change(ll x){
if(x==0) return "0";
string res="";
while(x){
res+=char(x%3+'0');
x/=3;
}
res+="0";
reverse(res.begin(),res.end());
return res;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--){
ll n;
cin>>n;
string now=change(n);
// cout<<n<<" base3 "<<now<<endl;
bool f=0;
for(char v:now){
if(v=='2') f=1;
}
if(!f){
cout<<n<<endl;continue;
}
int len=(int)now.length();
ll ans=0;
int id;
for(int i=0;i<len;i++){//找到第一个2
if(now[i]=='2'){
id=i;break;
}
}
int id2;
for(int i=id;i>=0;i--){//找到离2最近的0
if(now[i]=='0'){
id2=i;
now[i]='1';break;
}
}
for(int i=id2+1;i<len;i++) now[i]='0';//后面全为0
for(char c:now){
ans=ans*3+(c-'0');
}
cout<<ans<<endl;
}
return 0;
}
D1&D2
考虑贪心:每次选取最左边的被线段覆盖超过
k
k
k次的点,按照右端点从大到小删除覆盖该点的线段,依次模拟即可。
可以考虑使用
s
e
t
set
set,时间复杂度
O
(
n
l
o
g
(
n
)
)
O(nlog(n))
O(nlog(n))。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+100;
vector<pair<int,int> > seg[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,k,l,r;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>l>>r;
seg[l].push_back({r,i});
}
vector<int> del;
set<pair<int,int> > q;
for(int i=0;i<=2e5+1;i++){
for(auto v:seg[i]){
q.insert(v);
}
while(q.size()>k){
del.push_back(q.rbegin()->second);
q.erase(*q.rbegin());
}
while(!q.empty()&&q.begin()->first<=i) q.erase(*q.begin());//去掉没有覆盖i+1的
}
cout<<(int)del.size()<<endl;
for(int v:del) cout<<v<<' ';
cout<<endl;
}
E
简单 d p dp dp, d p i , 0 dp_{i,0} dpi,0和 d p i , 1 dp_{i,1} dpi,1代表到第 i i i层最后使用电梯还是楼梯的最小值,直接转移即可,时间复杂度 O ( n ) O(n) O(n)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+7;
ll dp[N][2];
ll a[N],b[N],ans[N];
int main(){
int n,c;
cin>>n>>c;
for(int i=2;i<=n;i++) cin>>a[i];//st
for(int i=2;i<=n;i++) cin>>b[i];//el
memset(dp,0x3f,sizeof(dp));
dp[1][0]=0;
dp[1][1]=c;
cout<<0;
for(int i=2;i<=n;i++){
dp[i][0]=min(dp[i-1][0]+a[i],dp[i-1][1]+a[i]);//st
dp[i][1]=min(dp[i-1][0]+b[i]+c,dp[i-1][1]+b[i]);//el
ans[i]=min(dp[i][0],dp[i][1]);
}
for(int i=2;i<=n;i++) cout<<' '<<ans[i];
cout<<endl;
return 0;
}