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

Claris發表於2017-11-26

A. Auxiliary Project

完全揹包。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
int f[1000005];
int g[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int main()
{
	freopen("auxiliary.in", "r", stdin); 
	freopen("auxiliary.out", "w", stdout);
	while(~scanf("%d",&n))
	{
		MS(f, -1);
		f[0] = 0;
		for(int i = 0; i <= n; ++i)
		{
			for(int j = 0; j < 10; ++j)
			{
				if(i - g[j] >= 0 && f[i - g[j]] >= 0)
				{
					gmax(f[i], f[i - g[j]] + j);
				}
			}
		}
		printf("%d\n", f[n]);
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

B. Boolean Satisfiability

設$t$為出現過的變數個數,若同時存在某個變數以及其反變數,則答案為$2^t$,否則答案為$2^t-1$。

#include<cstdio>
#include<cstring>
typedef long long ll;
const int N=100010;
bool v[N],neg[N];
char s[N];
int n,i;
int main(){
	freopen("boolean.in", "r", stdin); 
	freopen("boolean.out", "w", stdout);
	scanf("%s",s+1);
	n=strlen(s+1);
	for(i=1;i<=n;){
		if(s[i]=='|')i++;
		else if(s[i]=='~'){
			neg[s[i+1]]=1;
			i+=2;
		}else{
			v[s[i]]=1;
			i++;
		}
	}
	ll ans=1,flag=1;
	for(i=1;i<N;i++){
		if(v[i]||neg[i])ans*=2;
		if(v[i]&&neg[i])flag=0;
	}
	printf("%I64d",ans-flag);
}

  

C. Consonant Fencity

$O(2^{19})$列舉所有子音字母的大小寫即可。

#include<cstdio>
#include<cstring>
typedef long long ll;
const int N=1000010;
char s[N];
int n,i,j,mx,now,ans,S;
bool is[26],big[26];
int g[26][26],w[26][26],q[26],m;
int main(){
	freopen("consonant.in", "r", stdin); 
	freopen("consonant.out", "w", stdout);
	scanf("%s",s);
	n=strlen(s);
	for(i=1;i<n;i++){
		g[s[i-1]-'a'][s[i]-'a']++;
	}
	is['a'-'a']=1;
	is['e'-'a']=1;
	is['i'-'a']=1;
	is['o'-'a']=1;
	is['u'-'a']=1;
	is['w'-'a']=1;
	is['y'-'a']=1;
	for(i=0;i<26;i++)if(!is[i])q[m++]=i;
	for(i=0;i<26;i++)for(j=0;j<26;j++){
		if(is[i]||is[j])g[i][j]=0;
	}
	for(i=0;i<m;i++)for(j=0;j<m;j++)w[i][j]=g[q[i]][q[j]];
	for(S=0;S<1<<m;S++){
		now=0;
		for(i=0;i<m;i++)for(j=0;j<m;j++)if(((S>>i)^(S>>j))&1)now+=w[i][j];
		if(now>mx)mx=now,ans=S;
	}
	//printf("mx=%d\n",mx);
	S=ans;
	for(i=0;i<26;i++)big[i]=0;
	for(i=0;i<m;i++)if(S>>i&1)big[q[i]]=1;
	for(i=0;i<n;i++)if(big[s[i]-'a'])putchar(s[i]-'a'+'A');else putchar(s[i]);
}

  

D. Dividing Marbles

留坑。

 

E. Equal Numbers

令$goal=lcm(a_1,a_2,...,a_n)$,那麼對於每種數,可以變成另一個存在的倍數,或者直接變成$goal$。

按照代價從小到大合併即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e6 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
map<int, int>mop;
vector<int>vt[2];
int f[N];
int main()
{
	freopen("equal.in", "r", stdin); 
	freopen("equal.out", "w", stdout);
	while(~scanf("%d",&n))
	{
		mop.clear();
		for(int i = 1; i <= n; ++i)
		{
			int x;
			scanf("%d", &x);
			++mop[x];
		}
		int top = 1e6;
		for(int i = 0; i <= 1; ++i)vt[i].clear();
		for(auto it : mop)
		{
			int i = it.first;
			vt[0].push_back(it.second);
			for(int j = i + i; j <= top; j += i)if(mop.count(j))
			{
				vt[1].push_back(it.second);
				break;
			}
		}
		int ans = mop.size();
		MS(f, 63); f[0] = ans;
		
		int sum = 0;
		int sz = vt[1].size();
		sort(vt[1].begin(), vt[1].end());
		for(int j = 0; j < sz; ++j)
		{
			sum += vt[1][j];
			gmin(f[sum], ans - j - 1);
		}
		
		sum = 0;
		sz = vt[0].size();
		sort(vt[0].begin(), vt[0].end());
		for(int j = 0; j < sz; ++j)
		{
			sum += vt[0][j];
			gmin(f[sum], ans - j);
		}
		
		for(int i = 0; i <= n; ++i)
		{
			if(i)gmin(f[i], f[i - 1]);
			printf("%d ", f[i]);
		}
		puts("");
	}
	return 0;
}

/*
【trick&&吐槽】
6
3 4 1 2 1 2

【題意】


【分析】


【時間複雜度&&優化】


*/

  

F. Fygon 2.0

建立有向圖,邊$a\rightarrow b$表示$a\leq b$,那麼每個SCC中的變數都要相等。

縮完點之後得到一個$n$個點的DAG,那麼在漸進意義下,去掉等號時間複雜度不變,總複雜度為$n!$,而實際複雜度為拓撲序的個數,狀壓DP即可。

時間複雜度$O(n2^n)$。

#include<cstdio>
typedef long long ll;
const int N=50;
int n,m,i,j,k;
int g[N][N],f[N],e[N];
char s[100];
int vis[500],mark[N];
ll dp[1<<20];
inline int id(char x){
	if(x=='1')return -1;
	if(x=='n')return -1;
	if(vis[x]==-1)vis[x]=m++;
	return vis[x];
}
inline void add(int x,int y){//x<=y
	if(x<0||y<0)return;
	g[x][y]=1;
}
int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
inline void merge(int x,int y){
	if(F(x)!=F(y))f[f[x]]=f[y];
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
int main(){
	freopen("fygon20.in", "r", stdin); 
	freopen("fygon20.out", "w", stdout);
	scanf("%d",&n);
	n--;
	for(i=0;i<500;i++)vis[i]=-1;
	while(n--){
		scanf("%s",s);//for
		scanf("%s",s);
		int A=id(s[0]);
		scanf("%s",s);//in
		scanf("%s",s);
		int L=id(s[6]);
		scanf("%s",s);
		int R=id(s[0]);
		add(L,A);
		add(A,R);
	}
	for(k=0;k<m;k++)for(i=0;i<m;i++)for(j=0;j<m;j++)g[i][j]|=g[i][k]&&g[k][j];
	for(i=0;i<m;i++)f[i]=i;
	for(i=0;i<m;i++)for(j=0;j<m;j++)if(g[i][j]&&g[j][i])merge(i,j);
	for(i=0;i<m;i++)mark[i]=-1;
	n=0;
	for(i=0;i<m;i++)if(mark[F(i)]<0){
		mark[f[i]]=n++;
	}
	for(i=0;i<m;i++)for(j=0;j<m;j++)if(mark[f[i]]!=mark[f[j]]&&g[i][j])e[mark[f[i]]]|=1<<mark[f[j]];
	dp[0]=1;
	for(i=0;i<1<<n;i++)if(dp[i])for(j=0;j<n;j++)if(!(i>>j&1)&&!(e[j]&i))dp[i|(1<<j)]+=dp[i];
	ll U=dp[(1<<n)-1],D=1;
	for(i=2;i<=n;i++)D*=i;
	ll gc=gcd(U,D);
	U/=gc,D/=gc;
	printf("%d %lld/%lld",n,U,D);
}
/*
2
for i in range(1, n):
lag
  
4
for i in range(1, n):
for j in range(1, i):
for k in range(j, j):
lag

4
for i in range(1, n):
for j in range(1, i):
for k in range(i, j):
lag
*/

  

G. Grand Test

求出DFS樹,對於一條非樹邊$(u,v)$,暴力將$u$到$v$路徑上的樹邊染上這條非樹邊的顏色。

若一條樹邊被染了兩次色,則說明對應的兩個簡單環有公共邊。

僅保留兩個簡單環,任取兩個度數至少為$3$的點作為起點和終點,然後爆搜出所有路徑即可,一定恰好有$3$條簡單路徑。

時間複雜度$O(n+m)$。

#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
typedef pair<int,int>P;
const int N=100010,M=200010;
int Case,n,m,i,x,y,g[N],v[M<<1],nxt[M<<1],ed;
int vis[N],dfn,flag,f[N],d[N];
P col[N],A,B;
int S,T,p[N];
set<P>e;
inline void add(int x,int y){
	d[x]++;
	v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
}
void dfs(int x,int y){
	f[x]=y;
	vis[x]=++dfn;
	for(int i=g[x];i;i=nxt[i]){
		int u=v[i];
		if(u==y)continue;
		if(!vis[u]){
			dfs(u,x);
		}else if(vis[u]<vis[x]){
			int j=x;
			if(flag)continue;
			while(j!=u){
				if(col[j].first){
					flag=1;
					A=P(x,u);//down up
					B=col[j];
					break;
				}
				col[j]=P(x,u);
				j=f[j];
			}
		}
	}
}
inline void push(int x,int y){
	if(x>y)swap(x,y);
	e.insert(P(x,y));
}
inline void go(int x,int y){
	push(x,y);
	while(x!=y){
		push(x,f[x]);
		x=f[x];
	}
}
void dfs2(int x,int y,int z){
	p[z]=x;
	if(x==T){
		printf("%d",z);
		for(int i=1;i<=z;i++)printf(" %d",p[i]);
		puts("");
		return;
	}
	for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs2(v[i],x,z+1);
}
void solve(){
	scanf("%d%d",&n,&m);
	
	for(i=1;i<=n;i++)g[i]=vis[i]=f[i]=0;
	ed=dfn=flag=0;
	for(i=1;i<=n;i++)col[i]=P(0,0);
	
	while(m--){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(i=1;i<=n;i++)if(!vis[i]){
		dfs(i,0);
	}
	if(!flag){
		puts("-1");
		return;
	}
	e.clear();
	go(A.first,A.second);
	go(B.first,B.second);
	for(i=1;i<=n;i++)g[i]=d[i]=0;
	ed=0;
	for(set<P>::iterator it=e.begin();it!=e.end();it++){
		x=it->first;
		y=it->second;
		add(x,y);
		add(y,x);
	}
	S=T=0;
	for(i=1;i<=n;i++)if(d[i]>2){
		if(!S)S=i;
		else T=i;
	}
	printf("%d %d\n",S,T);
	dfs2(S,0,1);
}
int main(){
	freopen("grand.in", "r", stdin); 
	freopen("grand.out", "w", stdout);
	scanf("%d",&Case);
	while(Case--)solve();
}
/*
6 6
3 6
3 4
1 4
1 2
1 3
2 3
*/

  

H. Hidden Supervisors

貪心求出每個連通塊的最大匹配、根的匹配情況以及內部還未匹配的點數。

對於所有根已經匹配的連通塊,將其直接連到$1$上最優。

對於剩下的連通塊,按內部未匹配點數從大到小依次貪心連邊即可。

時間複雜度$O(n\log n)$。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
int fa[N];
int match[N];
vector<int>son[N];
vector<int>nomatch;
int ANS;
void dfs(int x)
{
	match[x] = 0;
	for(auto y : son[x])
	{
		dfs(y);
		if(!match[y] && !match[x])
		{
			match[y] = x;
			match[x] = y;
			++ANS;
		}
		if(!match[y])nomatch.push_back(y);
	}
}
struct A
{
	int sz;
	int rt;
	vector<int>vt;
	bool operator < (const A & b)const
	{
		return sz > b.sz;
	}
}a[N];
int main()
{
	freopen("hidden.in", "r", stdin); 
	freopen("hidden.out", "w", stdout);
	while(~scanf("%d",&n))
	{
		vector<int>rt;
		rt.push_back(1);
		for(int i = 1; i <= n; ++i)
		{
			son[i].clear();
		}
		for(int i = 2; i <= n; ++i)
		{
			scanf("%d", &fa[i]);
			if(fa[i] == 0)
			{
				rt.push_back(i);
			}
			else
			{
				son[fa[i]].push_back(i);
			}
		}
		
		ANS = 0;
		int rtsz = rt.size();
		int g = 0;
		vector<int>one;
		for(int i = 0; i < rtsz; ++i)
		{
			nomatch.clear();
			int x = rt[i];
			dfs(x);
			if(x == 1 || match[x])
			{
				fa[x] = 1;
				for(auto y : nomatch)
				{
					one.push_back(y);
				}
				if(x == 1 && !match[1])
				{
					one.push_back(1);
				}
			}
			else
			{
				++g;
				a[g].sz = nomatch.size();
				a[g].rt = x;
				a[g].vt = nomatch;
			}
		}
		sort(a + 1, a + g + 1);
		//
		//printf("treenum = %d\n", g);
		//
		for(int i = 1; i <= g; ++i)
		{
			int x = a[i].rt;
			if(one.size())
			{
				int ff = one.back();
				fa[x] = ff;
				one.pop_back();
				++ANS;
			}
			else
			{
				fa[x] = 1;
				one.push_back(x);
			}
			for(auto y : a[i].vt)
			{
				one.push_back(y);
			}
		}
		printf("%d\n", ANS);
		for(int i = 2; i <= n; ++i)printf("%d ", fa[i]);
		puts("");
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

I. Intelligence in Perpendicularia

答案$=$包圍盒周長$-$圖形周長。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e3 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
const LL INF = 1e9;
LL maxx, minx, maxy, miny;

struct A
{
	LL x, y;
}a[N];
int main()
{
	freopen("intel.in", "r", stdin); 
	freopen("intel.out", "w", stdout);
	scanf("%d", &n);
	maxx = -INF, maxy = -INF, minx = INF, miny = INF;
	for(int i = 0; i < n; i ++){
		scanf("%lld%lld", &a[i].x, &a[i].y);
		gmax(maxx, a[i].x);
		gmax(maxy, a[i].y);
		gmin(minx, a[i].x);
		gmin(miny, a[i].y);
	}a[n] = a[0];
	LL ans = 0;
	for(int i = 0; i < n; i ++){
		ans += abs(a[i].x - a[i + 1].x) + abs(a[i].y - a[i + 1].y);
	}
	ans -= (maxx - minx) * 2 + (maxy - miny) * 2;
	printf("%lld\n", ans);
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

J. Joker

分塊維護凸殼。

 

K. Kotlin Island

列舉行列分別切了幾刀即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m, g;
char s[105][105];
bool solve()
{
	MS(s, 0);
	int y = (n - 1) / 2;
	int x = (m - 1) / 2;
	for(int i = 0; i <= y; ++i)
	{
		for(int j = 0; j <= x; ++j)
		{
			if( (i + 1) * (j + 1) == g) 
			{
				for(int ii = 1; ii <= n; ++ii)
				{
					for(int jj = 1; jj <= m; ++jj)
					{
						if(ii % 2 == 0 && ii <= i * 2 || jj % 2 == 0 && jj <= j * 2)
						{
							s[ii][jj] = '#';
						}
						else
						{
							s[ii][jj] = '.';
						}
					}
				}
				return 1;
			}
		}
	}
	return 0;
}
int main()
{
	freopen("kotlin.in", "r", stdin); 
	freopen("kotlin.out", "w", stdout);
	while(~scanf("%d%d%d",&n, &m, &g))
	{
		if(!solve())puts("Impossible");
		else
		{
			for(int i = 1; i <= n; ++i)puts(s[i] + 1);
		}
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

L. Little Difference

若$n=2^k$形式則有無窮多個解,否則只能是$n=a^k$或$n=a^x(a+1)^y$的形式。

列舉$x,y$後二分$a$即可。

#include<cstdio>
typedef long long ll;
const ll lim=1000000000000000010LL;
ll n;
int ans;
inline ll mul(ll a,ll b){
	if(a>lim/b)return lim;
	a*=b;
	if(a>lim)a=lim;
	return a;
}
inline ll po(ll a,int b){
	ll t=1;
	while(b--){
		t=mul(t,a);
		if(t>=lim)return lim;
	}
	return t;
}
inline ll get1(int k){
	ll l=2,r=n,mid;
	while(l<=r){
		mid=(l+r)>>1;
		ll t=po(mid,k);
		if(t==n)return mid;
		if(t<n)l=mid+1;else r=mid-1;
	}
	return 2;
}
inline ll get2(int i,int j){
	ll l=2,r=n,mid;
	while(l<=r){
		mid=(l+r)>>1;
		ll t=mul(po(mid,i),po(mid+1,j));
		if(t==n)return mid;
		if(t<n)l=mid+1;else r=mid-1;
	}
	return 2;
}
int main(){
	freopen("little.in", "r", stdin); freopen("little.out", "w", stdout);
	scanf("%lld",&n);
	if(n<=2)return puts("-1"),0;
	if(n==(n&-n))return puts("-1"),0;
	//a^k
	for(int _=0;_<2;_++){
		for(int k=1;k<=70;k++){
			ll t=get1(k);//t>=2
			if(po(t,k)==n){
				if(_==0)ans++;
				else{
					printf("%d",k);
					for(int o=1;o<=k;o++)printf(" %lld",t);
					puts("");
				}
			}
		}
		for(int i=1;i<=70;i++)for(int j=1;j<=70;j++){
			ll t=get2(i,j);//t>=2
			if(mul(po(t,i),po(t+1,j))==n){
				if(_==0)ans++;
				else{
					printf("%d",i+j);
					for(int o=1;o<=i;o++)printf(" %lld",t);
					for(int o=1;o<=j;o++)printf(" %lld",t+1);
					puts("");
				}
			}
		}
		if(_==0)printf("%d\n",ans);
	}
}
/*
8589934592
2176782336
1000000000000000000
*/

  

相關文章