2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest 题解

A
签到

#include <iostream>
using namespace std;

#define int long long

int num[9];
signed main() {
	 freopen("auxiliary.in","r",stdin);
    freopen("auxiliary.out","w",stdout);

	int n;
	cin >> n;
	int t = n/3;
	int ans = 0;
	if (n%3==1) {
		ans = 4;
		t--;
	} else if (n%3==2) {
		ans = 1;
	}
	cout << t*7+ans << "\n";

	return 0;
}

B
签到

#include <iostream>
#include <string>
using namespace std;
using ll = long long;

bool exi[255][2];



int main() {
	freopen("boolean.in", "r", stdin);
	freopen("boolean.out", "w", stdout);
	string s;
	cin >> s;
	int n = s.size(), i = 0;

	while (i<n) {
		int flag = 0;
		if (s[i]=='~') flag = 1, i++;
		exi[s[i++]][flag] = 1;
	}
	ll ans = 1;
	int cnt1 = 0, cnt2 = 0;
	for (int i = 'a'; i<='z'; ++i) {
		if (exi[i][0]^exi[i][1]) cnt1++;
		else if (exi[i][0]) cnt2++;
	}
	for (int i = 'A'; i<='Z'; ++i) {
		if (exi[i][0]^exi[i][1]) cnt1++;
		else if (exi[i][0]) cnt2++;
	}
	ans = 1ll<<cnt1;
	if (cnt2==0) ans--;
	ans*=1ll<<cnt2;
	cout << ans ;
	return 0;
}

C
签到

#include <iostream>
#include <string>
using namespace std;
using ll = long long;

bool exi[255][2];



int main() {
	freopen("boolean.in", "r", stdin);
	freopen("boolean.out", "w", stdout);
	string s;
	cin >> s;
	int n = s.size(), i = 0;

	while (i<n) {
		int flag = 0;
		if (s[i]=='~') flag = 1, i++;
		exi[s[i++]][flag] = 1;
	}
	ll ans = 1;
	int cnt1 = 0, cnt2 = 0;
	for (int i = 'a'; i<='z'; ++i) {
		if (exi[i][0]^exi[i][1]) cnt1++;
		else if (exi[i][0]) cnt2++;
	}
	for (int i = 'A'; i<='Z'; ++i) {
		if (exi[i][0]^exi[i][1]) cnt1++;
		else if (exi[i][0]) cnt2++;
	}
	ans = 1ll<<cnt1;
	if (cnt2==0) ans--;
	ans*=1ll<<cnt2;
	cout << ans ;
	return 0;
}

D
unsolved
E
两种策略,一种是直接搞出lcm,然后剩余数字都可以贪心了。
一种是贪心的把所有不用搞lcm就能合并的数字合并了,即优先那些是因子的数。
然后两种策略每个位置取min输出

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=1000010;
class node
{
public:
	int num;
	int x;
	bool operator<(node n1)const{
		if(num!=n1.num) return num<n1.num;
		else return x<n1.x;
	}
};
int T,n,m;
map<int,int> mp;
int a[N];
int vec[N];
int dp[N];
int has[N];
int ans1[N],ans2[N];
int ap=0;
set<node> st;//维护块
vector<int> mi;
void add1(int x)
{
	for(int i=ap;i<ap+x-1;i++){
		ans1[i]=ans1[i-1];
	}
	ans1[ap+x-1]=ans1[ap+x-2]-1;
	ap=ap+x;
}
void add2(int x)
{
	for(int i=ap;i<ap+x-1;i++){
		ans2[i]=ans2[i-1];
	}
	ans2[ap+x-1]=ans2[ap+x-2]-1;
	ap=ap+x;
}
signed main()
{
	freopen("equal.in","r",stdin);
	freopen("equal.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		mp[a[i]]++;
	}
	for(auto it:mp){
		has[it.first]=it.second;
	}
	
	for(int i=1;i<=N;i++){//每个数字
		if(!has[i]) continue;
		for(int j=2*i;j<N;j+=i){
			if(has[j]){//之前的点如果有匹配显然不能合并
				//之前的点没有匹配,留着的话可以合并,如果变成inf显然也可以
				dp[i]=j;
				break;
			}
		}
		if(dp[i]==0) vec[has[i]]++;//数字数量为has[i]时,会剩下位置i
	}

	st.clear();
	for(auto it:mp){
		has[it.first]=it.second;
		st.insert(node{it.second,it.first});
	}
	ans1[ap++]=st.size();
	while(!st.empty()){
		int num=st.begin()->num;
		int cnt=0;
		while(!st.empty()&&st.begin()->num==num){
			st.erase(st.begin());
			cnt++;
		}
		cnt-=vec[num];//共有vec[num]个无法合并
		for(int i=0;i<vec[num];i++) mi.pb(num);
		for(int i=0;i<cnt;i++) add1(num);
	}
	if(mi.size()>=2){
		add1(mi[0]+mi[1]);
		for(int i=2;i<mi.size();i++){
			add1(mi[i]);
		}
	}

	mi.clear();
	ap=0;

	st.clear();
	for(auto it:mp){
		has[it.first]=it.second;
		st.insert(node{it.second,it.first});
	}
	ans2[ap++]=st.size();
	while(!st.empty()){
		int num=st.begin()->num;
		int cnt=0;
		while(!st.empty()&&st.begin()->num==num){
			st.erase(st.begin());
			cnt++;
		}
		cnt-=vec[num];
		for(int i=0;i<vec[num];i++) mi.pb(num);
		for(int i=0;i<cnt;i++) add2(num);
		if(mi.size()>=2){
			add2(mi[0]+mi[1]);
			for(int i=2;i<mi.size();i++){
				add2(mi[i]);
			}
			while(!st.empty()){
				auto tmp=st.begin()->num;
				st.erase(st.begin());
				add2(tmp);
			}
		}
	}
	
	for(int i=0;i<=n;i++) cout<<max(min(ans1[i],ans2[i]),1)<<' ';
	
}
/*
8
1 1 2 2 4 4 8 9

*/

F
unsolved,待补
G
tarjan,维护从当前点能到达的最low的点和次low的点,如果次low的点比当前点编号更小,说明有两条返祖边,说明可行,起点为当前点,终点为low2。还需要打印路径。因此额外维护返祖边的末端点。
参考链接:https://blog.csdn.net/ME495/article/details/83050131

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define pb push_back
const int N=200010;
int T,n,m;
int s,t;
vector<int> vec[N];
int low1[N],p1[N],low2[N],p2[N],dfn[N],fa[N],num[N];
int idx;
bool flag;
int vis[N];
queue<int> q;
vector<int> ans;
void upd(int x,int lo,int y)
{
	if(lo<low1[x]){
		low2[x]=low1[x];
		p2[x]=p1[x];
		low1[x]=lo;
		p1[x]=y;
	}
	else if(lo<low2[x]){
		low2[x]=lo;
		p2[x]=y;
	}
}
void printans()
{
	cout<<ans.size();
	for(auto it:ans) cout<<' '<<it;
	cout<<'\n';
	ans.clear();
}
void print(int x,int t)
{
	cout<<s<<' '<<t<<'\n';
	
	int cur=s;
	//第一条
	ans.pb(s);
	while(cur!=t){
		cur=fa[cur];
		ans.pb(cur);
	}
	printans();
	
	cur=p2[s];
	ans.pb(t);
	ans.pb(cur);
	while(cur!=s){
		cur=fa[cur];
		ans.pb(cur);
	}
	reverse(ans.begin(),ans.end());
	printans();

	cur=t;
	ans.pb(t);
	while(cur!=num[low1[x]]){
		cur=fa[cur];
		ans.pb(cur);
	}
	cur=p1[s];
	ans.pb(cur);
	while(cur!=s){
		cur=fa[cur];
		ans.pb(cur);
	}
	reverse(ans.begin(),ans.end());
	printans();

}
void tarjan(int x,int pa)
{
	dfn[x]=low1[x]=low2[x]=++idx;
	num[idx]=x;
	for(auto j:vec[x]){
		if(j==pa) continue;
		if(dfn[j]&&dfn[j]<dfn[x]){
			upd(x,dfn[j],x);
		}
		else if(dfn[j]==0){
			fa[j]=x;
			tarjan(j,x);
			upd(x,low1[j],p1[j]);
		}
	}
	if(!flag&&low2[x]<dfn[x]){
		flag=1;
		s=x;
		t=num[low2[x]];
		print(s,t);
	}
}
signed main()
{
	freopen("grand.in","r",stdin);
	freopen("grand.out","w",stdout);
	cin>>T;
	while(T--){
		cin>>n>>m;
		idx=flag=0;
		for(int i=0;i<=2*max(m,n);i++){
			vec[i].clear();
			dfn[i]=fa[i]=0;
			low1[i]=low2[i]=inf;
			p1[i]=p2[i]=vis[i]=0;
			num[i]=0;
		}
		for(int i=1;i<=m;i++){
			int u,v;
			cin>>u>>v;
			vec[u].pb(v);
			vec[v].pb(u);
		}
		for(int i=1;i<=n;i++){
			if(dfn[i]==0){
				tarjan(i,i);
			}
		}
		if(!flag){
			cout<<-1<<'\n';
		}
	}
}
/*
100

5 6
1 2
2 3
1 3
1 4
4 3
3 5

6 8
2 3
3 1
4 1
1 2
3 4
4 5
6 4
6 5


*/

H
dp每个无父亲的子树中空闲节点,以及根结点是否可能空闲。
然后贪心的优先将空闲节点多的子树加入1所在的子树中,如果之前有空闲节点且根空闲,那么可以匹配。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=200010;
class node
{
public:
	vector<int> fre;
	int is;//根结点是否空闲
	int id;
	bool operator<(node n1)const{
		if(id==1||n1.id==1) return id<n1.id;
		else if(fre.size()!=n1.fre.size()) return fre.size()>n1.fre.size();
		else if(is!=n1.is) return is<n1.is; 
		else return id<n1.id;
	}
}no[N];
int T,n,m;
int dp[N][2];
vector<int> vec[N];
int p[N];
int cnt=0;
deque<int> cfre;
void dfs(int x,int rt)
{
	int sum=0;
	vector<int> tmp;
	for(auto j:vec[x]){
		dfs(j,rt);
		if(dp[j][0]==dp[j][1]) tmp.pb(j);//优先把上面的留下
		sum+=dp[j][1];
	}
	if(tmp.empty()){//当前节点空下
		dp[x][0]=dp[x][1]=sum;
		if(x==rt) no[cnt].is=1;
	}
	else{
		dp[x][0]=dp[x][1]=sum;
		dp[x][1]++;
		for(int i=1;i<tmp.size();i++) no[cnt].fre.pb(tmp[i]);
	}
}
signed main()
{
	freopen("hidden.in","r",stdin);
	freopen("hidden.out","w",stdout);
	cin>>n;
	for(int i=2;i<=n;i++){
		cin>>p[i];
		if(p[i]) vec[p[i]].pb(i);
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(p[i]==0){
			dfs(i,i);
			no[cnt].id=i;
			cnt++;
			ans+=dp[i][1];
			//cout<<"|||"<<i<<' '<<ans<<' '<<cnt<<' '<<no[cnt-1].id<<' '<<no[cnt-1].is<<' '<<no[cnt-1].fre.size()<<'\n';
		}
	}
	sort(no,no+cnt);
	assert(no[0].id==1);
	int pre=0;
	if(no[0].is) cfre.pb(1);
	for(auto it:no[0].fre) cfre.pb(it);
	int cp=0;
	for(int i=1;i<cnt;i++){
		if(no[i].is){//空闲
			if(!cfre.empty()){
				int tmp=cfre.front();
				cfre.pop_front();
				p[no[i].id]=tmp;
				ans++;
			}
			else cfre.pb(no[i].id),p[no[i].id]=1;//当前根考虑和后面的匹配
		}
		else p[no[i].id]=1;//不空闲,直接和1连即可
		for(auto it:no[i].fre) cfre.pb(it);
	}
	cout<<ans<<'\n';
	for(int i=2;i<=n;i++) cout<<p[i]<<' ';
}
/*
10
0 0 0 0 0 0 0 0 0 

*/

I
签到

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int nums[2000106];
const int N = 1e6+7;
struct Edge {
	int l, r;
};

int main() {
	freopen("intel.in", "r", stdin);
	freopen("intel.out", "w", stdout);

	ios::sync_with_stdio(false);

	int n, x, y, lastx, lasty;
	cin >> n;
	cin >> lastx >> lasty;
	int prex = lastx, prey = lasty;
	vector<Edge> v1, v2;
	for (int i = 1; i<n; ++i) {
		cin >> x >> y;
		if (x==lastx) {
			int l = y, r = lasty;
			if (l>r) swap(l, r);
			r--;
			v1.push_back({l, r});
		} else {
			int l = x, r = lastx;
			if (l>r) swap(l, r);
			r--;
			v2.push_back({l, r});
		}
		lastx = x, lasty = y;
	}
	if (x==prex) {
		int l = y, r = prey;
		if (l>r) swap(l, r);
		r--;
		v1.push_back({l, r});
	} else {
		int l = x, r = prex;
		if (l>r) swap(l, r);
		r--;
		v2.push_back({l, r});
	}
	long long ans = 0;
	for (auto &[l, r]:v1) {
		nums[l+N]++, nums[r+N+1]--;
	}
	// ans+=nums[0];
	for (int i = 1; i<2000106; ++i) {
		nums[i]+=nums[i-1];
		if (nums[i]>2) ans+=nums[i]-2;
	}
	for (int i = 0; i<2000106; ++i) nums[i] = 0;
	for (auto &[l, r]:v2) {
		nums[l+N]++, nums[r+N+1]--;
	}
	for (int i = 1; i<2000106; ++i) {
		nums[i]+=nums[i-1];
		if (nums[i]>2) ans+=nums[i]-2;
	}
	cout << ans;
	return 0;
}

K
签到

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {
	freopen("kotlin.in", "r", stdin);
	freopen("kotlin.out", "w", stdout);
	int h, w, n;
	cin >> h >> w >> n;
	int nh, nw;
	nh = (h+1)/2, nw = (w+1)/2;
	int i = 1, j = 1;
	for (i = 1; i<=nh; ++i) {
		for (j = 1; j<=nw; ++j) {
			if (j*i==n) goto P;
		}
	}
	P: {}
	if (i*j==n) {
		// cout << i << "\n";
		i--, j--;
		vector<string> g(h, string(w, '.'));
		for (int t = 1; t<=i; ++t) {
			g[t*2-1] = string(w, '#');
		}
		for (int t = 1; t<=j; ++t) {
			for (int k = 0; k<h; ++k) {
				g[k][t*2-1] = '#';
			}
		}
		for (string &t:g) {
			cout << t << "\n";
		}
	} else {
		cout << "Impossible\n";
	}
	return 0;
}

L
(队友做的

#include<iostream>
#include<cmath>
#include<algorithm>
#include<string.h>
#include<vector>

#define lint int64_t
#define bint __int128

using
		namespace
					std;

lint n;
vector<vector<lint>> kotae;

bint qow(bint a,int b){
	
	bint ans=1;
	for(;b;a=a*a,b>>=1){
		if(b&1){
			ans=ans*a;
			if(ans>2e18) return 2e18;
		}
	}
	if(ans>2e18) return 2e18;
	return ans;
}

bint cal(bint p,int sz,int k){
	
	return qow(p,sz-k)*qow(p+1,k);
}

void check(int sz,int k){
	
	//cout<<"checking "<<sz<<' '<<k<<endl;
	
	bint l=2,r=pow(10,18./sz)*2.,mid;
	
	while(l<r){
		
		mid=(l+r)>>1;
		
		if(cal(mid,sz,k)<n){
			
			l=mid+1;
		}
		else{
			
			r=mid;
		}
	}
	
	if(cal(l,sz,k)==n){
		
		vector<lint> tem;
		
		for(int i=0;i<sz;i++){
			
			tem.push_back((lint)(i<sz-k?l:l+1));
		}
		
		kotae.push_back(tem);
		//printf("hit\n");
	}
	else{
		
		//printf("failed, l=%lld, ans=%lld\n",(lint)l,(lint)cal(l,sz,k));
	}
}

signed main(){
	
	freopen("little.in","r",stdin);
	freopen("little.out","w",stdout);
	
	scanf("%lld",&n);
	
	if(__builtin_popcountll(n)==1){
		
		printf("-1\n");
		return EOF+1;
	}
	
	vector<lint> tem;
	
	tem.push_back(n);
	kotae.push_back(tem);
	
	lint l=1,r=2e9,mid;
	
	while(l<r){
		
		mid=(l+r)>>1;
		
		if(mid*mid<n){
			
			l=mid+1;
		}
		else{
			
			r=mid;
		}
	}
	
	if(l*l==n){
		
		tem.clear();
		tem.push_back(l);
		tem.push_back(l);
		kotae.push_back(tem);
	}
	
	l=1,r=2e9,mid;
	
	while(l<r){
		
		mid=(l+r)>>1;
		
		if(mid*(mid+1)<n){
			
			l=mid+1;
		}
		else{
			
			r=mid;
		}
	}
	
	if(l*(l+1)==n){
		
		tem.clear();
		tem.push_back(l);
		tem.push_back(l+1);
		kotae.push_back(tem);
	}
	
	int limit=log2(n)+1;
	
	for(int sz=3;sz<=limit;sz++){
		
		for(int k=0;k<sz;k++){
			
			check(sz,k);
		}
	}
	
	printf("%u\n",kotae.size());
	
	for(vector<lint>& item:kotae){
		
		printf("%u",item.size());
		
		for(lint& it:item){
			
			printf(" %lld",it);
		}
		
		printf("\n");
	}
	
end:
	return EOF+1;
}
/*
996491789294632962
999999999999999989
3754371689208
20
1000000000000000000
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值