Codeforces Round #686 (Div. 3)

A: 错一位输出

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int mod = 998244353;
const int N = 2e5+10;
 
signed main(){
//	IOS
    #ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
    
    int tt; cin>>tt;
	while(tt --){
		int n; cin>>n;
		cout<<n<<" ";
		for(int i=1;i<n;i++) cout<<i<<" ";
		cout<<endl;
	}
    
    return 0;
}

B:
排序,枚举

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int mod = 998244353;
const int N = 2e5+10;

struct Node{
	int a,id;
	bool operator <(const Node &T)const{
		return a < T.a;
	}
}node[N];

signed main(){
//	IOS
    #ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
    
    int tt; cin>>tt;
	while(tt --){
		map<int,int> mp;
		int n; cin>>n;
		for(int i=0;i<n;i++){ 
			int a; cin>>a;
			node[i] = {a,i+1};
			mp[a] ++;
		}
		sort(node,node+n);
		int t = -1;
		for(int i=0;i<n && t == -1;i++){
			if(mp[node[i].a] == 1){
				t = node[i].id;
				break;
			}
		}
		cout<<t<<endl;
	}
    
    return 0;
}

C:
把每个值对应的位置放到一堆,去计算这些点间有多少个区间(取最小值),注意左右边界的情况。

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
//#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int mod = 998244353;
const int N = 2e5+10;

int a[N];
vector<int> ve[N];
signed main(){
//	IOS
    #ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
    
    int tt; cin>>tt;
	while(tt --){
		int n,cnt = 0; cin>>n;
		for(int i=0;i<n;i++) cin>>a[i],ve[i+1].clear();
		ve[a[0]].push_back(0);
		for(int i=1;i<n;i++){
			if(a[i] != a[i-1]){
				ve[a[i]].push_back(i);
				cnt  = i;
			}
		}
		int mi = INF,res = 0;
		for(int i=1;i<=n;i++){
			if((int)ve[i].size()){
				res = (int)ve[i].size() - 1;
				if(ve[i][0] != 0) res ++;
				if(ve[i][(int)ve[i].size()-1] != cnt) res ++;
				mi = min(res,mi);
			}
		}
//		cout<<"cnt :"<<cnt<<endl;
		cout<<mi<<endl;
	}
    
    return 0;
}

D:
用唯一分解定律分解出来,之后取出次数最大的,留一个全部输出,再输出剩下之积。
可以知道这样取是保证个数最多的。

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int mod = 998244353;
const int N = 2e5+10;

int p[N],c[N];

signed main(){
//	IOS
    #ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
    
    int tt; cin>>tt;
	while(tt --){
		int n; cin>>n;
		memset(p,0,sizeof(p));
		memset(c,0,sizeof(c));
		int cnt = 0,ma = -INF,t = 0;
		for(int i=2;i<=n/i;i++){
			if(n % i == 0){
				p[++cnt] = i;
				while(n % i == 0) c[cnt] ++,n /= i;
				if(c[cnt] > ma){
					ma = c[cnt];
					t = i;
				}
			}
		}
		if(n > 1) p[++cnt] = n,c[cnt] = 1;
		if(c[cnt] > ma){
			ma = c[cnt];
			t = n;
		}
		int res = 1;
		cout<<ma<<endl;
		if(ma == 1){
			for(int i=1;i<=cnt;i++){
				while(c[i] --) res *= p[i];
			}
		}
		else{
			for(int i=1;i<=cnt;i++){
				if(t == p[i]) c[i] = 1;
				while(c[i] --) res *= p[i];
			}
			while(ma-- > 1) cout<<t<<" ";
		}
		cout<<res<<endl;
	}
    return 0;
}

E:
提上的信息可以知道,n个点n-1条边是一棵数,n个点n条边是有一个环,然后环上的各个点作为根节点,构成各自的树。

对于不同树上的点,可以有两条路径。对于同一棵树上的点,只有一条。
(先不考虑同一棵树)总共的路径就有n*(n-1)/2 * 2 = n * (n-1) (n为总节点数)
之后再减去同一棵树上的路径就行了。
对于同一棵树上的路径为(m-1)*m/2 (m为节点数)

这样,把每棵数的节点维护到环上对应的点,最后去遍历环上的点,就好计算。

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int mod = 998244353;
const int N = 4e5+10;

int ne[N],h[N],e[N],idx=1;
int d[N],si[N],n;
bool vis[N];

void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void top_sort(){
	queue<int> qe;
	for(int i=1;i<=n;i++){
		if(d[i] == 1){
			qe.push(i);
			vis[i] = true;
		}
	}
	int res = n*(n-1);
	while(!qe.empty()){
		int t = qe.front();qe.pop();
		for(int i=h[t];i;i=ne[i]){
			int j = e[i];
			if(--d[j] == 1) {
				vis[j] = true;
				qe.push(j);
			}
			si[j] += si[t];
		} 
	}
	// 遍历环上的点
	for(int i=1;i<=n;i++){
		if(!vis[i]) res -= si[i]*(si[i]-1)/2;
	}
	cout<<res<<endl;
}

signed main(){
	IOS
    #ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
    
    int tt; cin>>tt;
	while(tt --){
		idx = 1;
		cin>>n;
		for(int i=1;i<=n;i++){
			si[i] = 1; vis[i] = false;
			h[i] = h[i+n] = 0;
			d[i] = 0;
		}
		for(int i=0;i<n;i++){
			int a,b; cin>>a>>b;
			add(a,b); add(b,a);
			d[b]++,d[a]++;
		}
		top_sort();
	}
    return 0;
}

F:

假设固定好左端,即l,则r我们可以分出下列几种情况。

if( max(1,l-1) != min(l,r) )
此时 if( max(1,l-1) > min(l,r) )  只有把r往左移,才可能使得min(l,r)增大。
否则往右移

else 

if( min(l,r) == max(r+1,n)) 找到一个合法方案
else if( min(l,r) < max(r+1,n)) 此时只有将r往左移动,才可能使min(l,r)变大,或往右max(r+1,n)才减小。
而左边的两个区间都已经确定好了,r往左移只会让左边的区间不相等且只会使右边区间增大,故只能往右移。
否则往左移

所以我们可以遍历固定l,二分r,找到了一个满足条件就输出。
对于区间最值,用ST表。

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
//#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int mod = 998244353;
const int N = 2e5+10;

int dpmax[N][50],dpmin[N][50];
int H[N],a[N],n;
bool plas;

void ST_prework(){
	int t = H[n] + 1;
	for(int i=1;i<=n;i++) dpmax[i][0] = dpmin[i][0] = a[i];
	for(int j=1;j<t;j++)
		for(int i=1;i<=n-(1<<j)+1;i++){
			dpmax[i][j] = max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]);
			dpmin[i][j] = min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]);
		}
}

int ST_askmax(int l,int r){
	int k = H[(r - l + 1)];
	return max(dpmax[l][k],dpmax[r-(1<<k)+1][k]);
}

int ST_askmin(int l,int r){
	int k = H[(r - l + 1)];
	return min(dpmin[l][k],dpmin[r-(1<<k)+1][k]);
}

bool check(int l,int r){
	if(ST_askmin(l,r) != ST_askmax(1,l-1)){
		return ST_askmin(l,r) > ST_askmax(1,l-1);
	}else{
		if(ST_askmin(l,r) == ST_askmax(r+1,n)) plas = true;
		return ST_askmin(l,r) < ST_askmax(r+1,n);
	}
}

signed main(){
	IOS
    #ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
    for(int i=1;i<N;i++) H[i] = log(i)/log(2);
    int tt; cin>>tt;
    while(tt --){
    	cin>>n;
    	plas = false;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	ST_prework();
    	for(int i=2;i<=n&&!plas;i++){
    		int l = i,r = n-1;
    		while(l <= r){
    			int mid = (l + r) >>1;
    			if(mid >= n) break;
    			if(check(i,mid)) l = mid + 1;
    			else r = mid - 1;
    			if(plas){
    				cout<<"YES"<<endl;
    				cout<<i-1<<" "<<mid-i+1<<" "<<n-mid<<endl;
    				break;
				}
			}
		}
    	if(!plas) cout<<"NO"<<endl;
	}
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值