比赛连接:Dashboard - CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!) - Codeforces
A. Beautiful Sequence
题意:
t(1≤t≤500)组测试每组给定大小为n(1≤n≤100) 的序列,判断它是否存在一个子序列是好序列。一个序列是好序列当且仅当至少存在一个ai=i。
思路:
考虑到从原序列抽取一些数形成的子序列下标i只可能比原来小,如果原来存在一个i>=a[i],存在一种选择方法使得子序列下标i减小到a[i],否则不可能构造出来。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<iomanip>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define all(x) (x).begin(),(x).end()
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const db pi=acos(-1.0);
const int N=110,M=2*N;
int a[N];
inline void solve()
{
int n;
cin>>n;
rep(i,1,n+1) cin>>a[i];
rep(i,1,n+1){
if(i>=a[i]){
cout<<"YES"<<endl;
return;
}
}
cout<<"NO"<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}
B. Candies
题意:
t(1≤t≤1e4)组测试每组给定n(2≤n≤1e9) ,有两种操作,第一种是将x变为2*x-1,第二种是将x变为2*x+1,输出将1变为n的操作序列,最多不超过40次。
思路:
操作后的数只能变为奇数,故n为偶数时一定不能构造。n为奇数,考虑如何使n变为1,如果把n写为二进制形式,第一种逆操作相当于将n加一再右移一位,第二种为将n减一再右边移动一位,所以可以找到一种操作:每一次看n的最后两位,如果是11做第二种操作,这样就除去了最后一位,如果是01做第一种操作(不能做第二种操作,因为过程中不能出现偶数)。n的最大是1e9,最多30位,一定符合要求。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<iomanip>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define all(x) (x).begin(),(x).end()
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const db pi=acos(-1.0);
const int N=40,M=2*N;
int a[N],b[N];
inline void solve()
{
int n;
cin>>n;
if(n&1){
int len=0,sz=0;
while(n){
a[++len]=n&1;
n>>=1;
}
cout<<len-1<<endl;
rep(i,1,len){
if(a[i+1]) b[++sz]=2;
else b[++sz]=1,a[i+1]=1;
}
per(i,sz,0) cout<<b[i]<<" ";
cout<<endl;
}else cout<<-1<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}
C. Make It Permutation
题意:
给定一个序列,可以进行两种操作,删除一个元素,花费为c,添加一个元素,花费为d,求使序列变为一个非空排列的最小花费。
思路:
因为排列不会存在重复元素,遇到重复元素一定要删除。将处理后的数组排序,考虑构造出1~a[i]的排列,删除后面的元素的花费,所有情况取最小值。注意将数组删除为空再补1的情况也要算。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<iomanip>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define all(x) (x).begin(),(x).end()
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const db pi=acos(-1.0);
const int N=1e5+10,M=2*N;
int a[N],len;
inline void solve()
{
len=0;
set<int>st;
int n,c,d,x;
LL ans=0;
cin>>n>>c>>d;
rep(i,1,n+1){
cin>>x;
if(st.count(x)) ans+=c;
else st.insert(x),a[++len]=x;
}
sort(a+1,a+1+len);
LL mi=1e18,tot=0;
rep(i,1,len+1){
tot+=a[i]-a[i-1]-1;
mi=min(mi,tot*d+(LL)(len-i)*c);
}
mi=min(mi,(LL)len*c+d);
cout<<ans+mi<<endl;
}
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
// #endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}
D. Climbing the Tree
题意:
一个蜗牛爬树,树的高度为h,蜗牛每天爬a,下降b(a>b),从高度0花费n天爬上高度h。现在不知道h的值,有两种事件,事件1是给定a,b,n,需判断当前事件是否和前面的冲突;时间2是给定a,b,判断是否能根据当前信息求出确切的n。
思路:
先寻找a,b,h,n的关系,因为最后一次距离顶端小于等于a可以直接上去,考虑爬高度h-a的情况,显然需要天,最后再花一天爬上h,总天数为
对于事件1,有:
于是可以根据a,b,n的值算出h的下界和上界,分别用lh和rh表示:
将lh和rh和前面的取交集,如果为空说明不合法,否则合法。
对于事件2,根据当前lh和rh可以根据上式计算出n,n唯一则说明有解,否则无解。
注意h<=a,n=1的边界情况。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<iomanip>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define all(x) (x).begin(),(x).end()
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const db pi=acos(-1.0);
const int N=1e5+10,M=2*N;
int n;
void cal(int a,int b,LL &lh,LL &rh)
{
if(n==1){
lh=1,rh=a;
return;
}
LL t=1ll*(n-2)*(a-b)+a;
lh=t+1,rh=t+a-b;
}
LL calc(int a,int b,LL h)
{
if(h<=a) return 1;
LL res=(h-a)/(a-b);
if((h-a)%(a-b)) res+=2;
else res+=1;
return res;
}
inline void solve()
{
LL lh=-1,rh=1e18;
int q;
cin>>q;
rep(_,0,q){
int op,a,b;
cin>>op>>a>>b;
if(op==1){
cin>>n;
if(_){
LL l,r;
cal(a,b,l,r);
if(l>rh||r<lh) cout<<0<<" ";
else cout<<1<<" ",lh=max(lh,l),rh=min(rh,r);
}else{
cout<<1<<" ";
cal(a,b,lh,rh);
}
//cout<<lh<<" "<<rh<<endl;
}else{
if(lh==-1){
cout<<-1<<" ";
continue;
}
LL n1=calc(a,b,lh),n2=calc(a,b,rh);
if(n1==n2) cout<<n1<<" ";
else cout<<-1<<" ";
}
}
cout<<endl;
}
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
// #endif
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}
E. Monsters
题意:
给定一个n个点,m条边的无向无环图,每个点都有一个怪物对应一个危险值,能打败某个点的怪物当且仅当打败的怪物数大于等于危险值。开始选择一个点出发,可以通过一个点需要能打败该点的怪物,判断能否打败所有怪物。
n, m (1≤n,m≤2e5)
思路:
本题官方给出了最暴力的做法:找到每一个ai=0的点做扩散,每一次扩散判断是否能扩展到所有点。虽然直觉上会超时,但是可以证明这样做复杂度为O(n*log(n)*log(n))。
相比官方做法更容易想到用并查集维护连续可走的块。先将危险值从小到大排序,需要一个数组来记录一个集合是否被选择(是否走过),每一次扩散都将危险值大的点并到危险值小的点,维护集合大小,最后合法的结果是一定只有一个根节点。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include<bitset>
#include<iomanip>
#include<list>
#include <algorithm>
#define pii pair<int,int>
#define pll pair<LL,LL>
#define pil pair<int,LL>
#define pli pair<LL,int>
#define pdd pair<db,db>
#define se second
#define fi first
#define endl '\n'
#define rep(i,a,b) for (register int i=a;i<b;++i)
#define per(i,a,b) for (register int i=a;i>b;--i)
#define MEM(a,x) memset(a,x,sizeof(a))
#define all(x) (x).begin(),(x).end()
#define M(x) ((x)%MOD)
#define db double
#define eps 1e-9
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MOD=1e9+7;
const db pi=acos(-1.0);
const int N=2e5+10,M=2*N;
pii p[N];
int h[N],e[M],ne[M],idx,s[N],d[N],ok[N],vis[N],sz[N];
void add(int a,int b)
{
e[++idx]=b,ne[idx]=h[a],h[a]=idx;
}
int find(int x)
{
if(x==s[x]) return s[x];
return s[x]=find(s[x]);
}
inline void solve()
{
idx=0;
MEM(h,0);
int n,m;
cin>>n>>m;
rep(i,1,n+1) cin>>p[i].fi,p[i].se=i,s[i]=i,ok[i]=0,vis[i]=0,sz[i]=1;
sort(p+1,p+1+n);
rep(i,0,m){
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
rep(_,1,n+1){
int u=p[_].se;
if(p[_].fi==0) ok[u]=1;
vis[u]=1;
for(int i=h[u];i;i=ne[i]){
int v=e[i];
if(!vis[v]) continue;
u=find(u),v=find(v);
if(sz[v]>=p[_].fi&&ok[v]) ok[u]=1;
if(u!=v){
sz[u]+=sz[v];
s[v]=u;
}
}
}
if(!ok[find(1)]){
cout<<"NO"<<endl;
return;
}
rep(i,2,n+1) if(find(i)!=find(1)){
cout<<"NO"<<endl;
return;
}
cout<<"YES"<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}