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

Claris發表於2017-11-26

A. Advertising Strategy

最優策略一定是第一天用$y$元,最後一天再用$x-y$元補滿。

列舉所有可能的$y$,然後模擬即可,天數為$O(\log n)$級別。

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

#include<cstdio>
typedef long long ll;
const ll inf=1LL<<60;
ll min(ll a,ll b){return a<b?a:b;}
ll cal(ll n,ll x,ll o){
	ll ans=1;
	ll a=0,b,k,pre;
	while(1){
		pre=a;
		k=min(n-a,x);
		b=a+k;
		x-=k;
		a=b+min(b,(n-b)/2);
		if(a==n)return ans;
		if(a+o>=n)return ans+1;
		if(a==pre)return inf;
		ans++;
	}
}
int main(){
	ll n,x;
	scanf("%lld%lld",&n,&x);
	ll ans=inf;
	for(int i=0;i<x;i++)ans=min(ans,cal(n,x-i,i));
	printf("%lld",ans);
}

  

B. Byteland Trip

留坑。

 

C. Carpet

對樹進行輕重鏈剖分,那麼把重兒子往右掛,輕兒子往下掛即可。層數$O(\log n)$。

#include<cstdio>
const int N=100010,K=25;
int n,i,x,y,g[N],v[N<<1],nxt[N<<1],ed,size[N],son[N];
int X[N],Y[N];
int cnt[K];
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int y){
	size[x]=1;
	for(int i=g[x];i;i=nxt[i])if(v[i]!=y){
		dfs(v[i],x);
		size[x]+=size[v[i]];
		if(size[v[i]]>size[son[x]])son[x]=v[i];
	}
}
void dfs2(int x,int y,int z){
	Y[x]=z;
	X[x]=++cnt[z];
	for(int i=g[x];i;i=nxt[i])if(v[i]!=y&&v[i]!=son[x])dfs2(v[i],x,z+1);
	if(son[x])dfs2(son[x],x,z);
}
int main(){
	scanf("%d",&n);
	for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	dfs(1,0);
	dfs2(1,0,1);
	for(i=1;i<=n;i++)printf("%d %d\n",X[i],Y[i]);
}

  

D. Decoding of Varints

按題意模擬即可。

#include<cstdio>
typedef unsigned long long ll;
int n,x;ll ans,len;
int main(){
	scanf("%d",&n);
	ans=0;
	len=1;
	while(n--){
		scanf("%d",&x);
		if(x<128){
			ans+=1ULL*x*len;
			if(ans%2==0){
				printf("%llu\n",ans/2);
			}else{
				printf("-%llu\n",ans/2+1);
			}
			ans=0;
			len=1;
		}else{
			ans+=1ULL*(x-128)*len;
			len*=128;
		}
	}
}

  

E. Empire History

留坑。

 

F. Fake or Leak?

設部分終榜裡排名最高的隊伍為$A$,最低的為$B$,那麼對於每個沒出現的隊伍,有兩種可能:

$1.$最壞情況:封榜後一題也沒有通過,檢查是否比$B$還靠後。

$2.$最好情況:封榜後立即AK了,檢查是否比$A$還靠前。

#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 = 1010, 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, k;
string s[N], s2[N];
char ch[N][30], ch2[N][30];
int num[N][30], num2[N][30], tim[N][30], tim2[N][30];
int solvenum[N], solvenum2[N], solvetim[N], solvetim2[N], solvelst[N], solvelst2[N];
map<string, int> mop, visit;

int compare(int x, int y)	// x solve  y solve2
{
	if(solvenum[x] > solvenum2[y]) return 1;
	else if(solvenum[x] < solvenum2[y]) return -1;
	if(solvetim[x] > solvetim2[y]) return -1;
	else if(solvetim[x] < solvetim2[y]) return 1;
	if(solvelst[x] > solvelst2[y]) return -1;
	else if(solvelst[x] < solvelst2[y]) return 1;
	else if(s[x] < s2[y]) return 1; 	//
	else return -1;
}

int main()
{
	scanf("%d%d%d",&k, &n, &m);
	mop.clear();
	MS(solvelst, 0); MS(solvelst2, 0); MS(solvenum, 0); MS(solvenum2, 0); MS(solvetim, 0); MS(solvetim2, 0);
	for(int i = 1; i <= n; i ++){
		//scanf("%s", s[i]);
		cin >> s[i];
		mop[s[i]] = i;
		for(int j = 1; j <= k; j ++){
			scanf(" %c%d%d", &ch[i][j], &num[i][j], &tim[i][j]);
			//printf("%c %d %d\n", ch[i][j], num[i][j], tim[i][j]);
			if(ch[i][j] == '+'){
				solvenum[i] ++;
				solvetim[i] += (num[i][j] - 1) * 20 + tim[i][j];
				gmax(solvelst[i], tim[i][j]);
			}
		}
	}
	visit.clear();
	for(int i = 1; i <= m; i ++){
		//scanf("%s", s2[i]);
		cin >> s2[i];
		visit[s2[i]] = 1;
		for(int j = 1; j <= k; j ++){
			scanf(" %c%d%d", &ch2[i][j], &num2[i][j], &tim2[i][j]);
			if(ch2[i][j] == '+'){
				solvenum2[i] ++;
				solvetim2[i] += (num2[i][j] - 1) * 20 + tim2[i][j];
				gmax(solvelst2[i], tim2[i][j]);
			}
		}
	}
	if(m == 1){
		puts("Leaked");
		return 0;
	}
	int FLAG = 1;
	for(int i = 1; i <= n; i ++){
		if(visit[s[i]] == 0){
			int flag = 0;
			if(compare(i, 1) > 0 || compare(i, m) < 0) flag = 1;
			for(int j = 1; j <= k; j ++){	// AK
				if(ch[i][j] == '-'){
					solvenum[i]	++;
					solvetim[i] += (num[i][j]) * 20 + 240;
					gmax(solvelst[i], 240);
				}
				else if(ch[i][j] == '.'){
					solvenum[i] ++;
					solvetim[i] += 240;
					gmax(solvelst[i], 240);
				}
			}
			if(compare(i, 1) > 0 || compare(i, m) < 0) flag = 1;
			if(!flag) FLAG = 0;
		}
	}
	if(FLAG) puts("Leaked");
	else puts("Fake");
	//scanf("%d", &n);
	return 0;
}

/*
【trick&&吐槽】
3 3 2
crabs + 1 1 + 1 2 + 1 3
lions . 0 0 - 5 239 . 0 0
wombats . 0 0 . 0 0 . 0 0
wombats + 1 241 + 3 299 - 22 299
lions + 1 241 + 6 240 - 3 299

3 4 2
crabs + 1 1 + 1 2 + 1 3
lions . 0 0 + 5 239 . 0 0
wolves . 0 0 . 0 0 . 0 0
wombats . 0 0 . 0 0 . 0 0
crabs + 1 1 + 1 2 + 1 3
wombats . 0 0 + 2 299 . 0 0

【題意】


【分析】


【時間複雜度&&優化】


*/

  

G. God of Winds

設$f[i][j]$表示$(i,j)$操作次數,那麼可以表示成$A-B=C$的限制,檢查是否矛盾即可。

#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
typedef long long ll;
const int N=550,M=N*N;
int n,m,cnt,i,j,id[N][N],x,A,B,g[M],v[M*4],w[M*4],nxt[M*4],ed;
bool vis[M];
ll f[M];
inline void add(int x,int y,int z){
v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;
//printf("%d %d %d\n",x,y,z);
}//x - y = z
void dfs(int x,ll y){
	if(vis[x]){
		if(f[x]!=y){
			puts("No");
			exit(0);
		}
		return;
	}
	vis[x]=1;
	f[x]=y;
	for(int i=g[x];i;i=nxt[i]){
		dfs(v[i],f[x]-w[i]);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(i=0;i<n;i++)for(j=0;j<m;j++)id[i][j]=++cnt;
	for(i=0;i<n;i++)for(j=0;j<m;j++){
		B=id[i][j];
		
		
		
		scanf("%d",&x);
		A=id[(i-1+n)%n][j];
		add(B,A,-x);
		add(A,B,x);
		
		scanf("%d",&x);
		A=id[i][(j-1+m)%m];
		add(B,A,x);
		add(A,B,-x);
	}
	for(i=1;i<=cnt;i++)if(!vis[i])dfs(i,0);
	puts("Yes");
}

  

H. Hilarious Cooking

可行的$T$是一個區間,求出$T$的最小值和最大值即可。

#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;
LL T, n, m;
LL a[N], b[N];
LL cnt(LL a, LL b)
{
	//a should <= b
	if(a > b)return 0;
	if(b < 0)return 0;
	
	LL num = (b - a + 1);
	
	LL negnum = a < 0 ? abs(a) : 0;
	LL sub = (1 + negnum) * negnum / 2;
	
	return (a + b) * num / 2 + sub;
}
bool check()
{
	LL BOT = 0;
	LL TOP = 0;
	for(int i = 1; i <= m; ++i)
	{
		BOT += b[i];
		TOP += b[i];
	}
	for(int i = 1; i < m; ++i)
	{
		LL pos_dif = a[i + 1] - a[i];
		LL val_dif = abs(b[i + 1] - b[i]);
		LL mx = max(b[i + 1], b[i]);
		LL mn = min(b[i + 1], b[i]);
		if(val_dif > pos_dif)
		{
			//
			//puts("TOO MUCH VAL_DIF");
			//
			return 0;
		}
		if(pos_dif == 1)continue;
		LL top = mx + (pos_dif - val_dif) / 2;
		LL bot = mn - (pos_dif - val_dif) / 2;		
		if(val_dif % 2 == pos_dif % 2)
		{
			TOP += cnt(mx, top) + cnt(mn, top) - max(top, 0ll);
			BOT += cnt(bot, mx) + cnt(bot, mn) - max(bot, 0ll);
		}
		else
		{
			TOP += cnt(mx, top) + cnt(mn, top);
			BOT += cnt(bot, mx) + cnt(bot, mn);
		}
		TOP -= mn + mx;
		BOT -= mn + mx;
	}
	
	{
		//1:
		LL top = b[1] + (a[1] - 1);
		LL bot = b[1] - (a[1] - 1);
		TOP += cnt(b[1] + 1, top);
		BOT += cnt(bot, b[1] - 1);
		//
		//printf("pretop = %lld, prebot = %lld\n", top, bot);
		//
	}
	{
		//m:
		LL top = b[m] + (n - a[m]);
		LL bot = b[m] - (n - a[m]);
		TOP += cnt(b[m] + 1, top);
		BOT += cnt(bot, b[m] - 1);
		//
		//printf("subtop = %lld, subbot = %lld\n", top, bot);
		//
	}
	//
	//printf("TOP = %lld, BOT = %lld\n", TOP, BOT);
	//
	return BOT <= T && TOP >= T;
}
int main()
{
	while(~scanf("%lld%lld%lld",&T, &n, &m))
	{
		for(int i = 1; i <= m; ++i)
		{
			scanf("%lld%lld", &a[i], &b[i]);
		}
		puts(check() ? "Yes" : "No");
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

I. Infinite Gift

將每個向量模$2$後壓位高斯消元檢查是否有解即可。時間複雜度$O(\frac{nk^2}{64})$。

#include<cstdio>
#include<bitset>
using namespace std;
const int N=1510;
int n,m,i,j,k,x;bitset<N>g[N];
int main(){
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++){
    for(j=1;j<=m;j++){
      scanf("%d",&x);
      if(x%2)g[i][j]=1;
    }
    g[i][0]=1;
  }
  for(i=j=1;i<=m;i++){
    for(k=j;k<=n;k++)if(g[k][i])break;
    if(k>n)continue;
    swap(g[k],g[j]);
    for(k=j+1;k<=n;k++)if(g[k][i])g[k]^=g[j];
    j++;
  }
  for(;j<=n;j++)if(g[j][0])return puts("No"),0;
  puts("Yes");
}

  

J. Judging the Trick

取一條水平線,做縱向的一維線段覆蓋,若有解則找到了一組可行解。

否則注意到三角形總面積小於矩形面積,故求出水平線左右側的三角形總面積和矩形面積,根據這個條件判斷哪邊存在解,然後縮小範圍即可。

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

#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;
const long double eps = 1e-11;
int sgn(long double x)
{
	if(fabs(x) < eps) return 0;
	return x > 0 ? 1 : -1;
}
long double sqr(long double x){return  x * x;}
struct point
{
	long double x, y;
	point(){}
	point(long double a, long double b):x(a), y(b) {}
	friend point operator + (const point &a, const point &b){
		return point(a.x + b.x, a.y + b.y);
	}
	friend point operator - (const point &a, const point &b){
		return point(a.x - b.x, a.y - b.y);
	}
	friend bool operator == (const point &a, const point &b){
		return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
	}
	friend point operator * (const point &a, const long double &b){
		return point(a.x * b, a.y * b);
	}
	friend point operator * (const long double &a, const point &b){
		return point(a * b.x, a * b.y);
	}
	friend point operator / (const point &a, const long double &b){
		return point(a.x / b, a.y / b);
	}
	long double norm(){
		return sqrt(sqr(x) + sqr(y));
	}
};

long double det(const point &a, const point &b)
{
	return a.x * b.y - a.y * b.x;
}
long double dot(const point &a, const point &b)
{
	return a.x * b.x + a.y * b.y;
}
struct line
{
	point a, b;
	line(){}
	line(point x, point y) : a(x), b(y) {}
};

bool PointOnSegment(point p, point s, point t)
{
	return sgn(det(p - s, t - s)) == 0 && sgn(dot(p - s, p - t)) <= 0;
}
bool parallel(line a, line b)
{
	return !sgn(det(a.a - a.b, b.a - b.b));
}
bool line_make_point(line a, line b, point &res)
{
	if(parallel(a, b)) return false;
	long double s1 = det(a.a - b.a, b.b - b.a);
	long double s2 = det(a.b - b.a, b.b - b.a);
	res = (s1 * a.b - s2 * a.a) / (s1 - s2);
	return true;
}


bool cmp(line l1, line l2)
{
	return l1.a.y < l2.a.y;

}

long double area(point o, point a, point b)
{
	return fabs((a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x));
}

int  m, k;

point a[N][4];
line seg[N], SEG[N];




bool check(long double mid, long double &larea, long double &rarea)
{
	line ll;
	ll.a = point(mid, 0), ll.b = point(mid, m);
	int segn = 0;
	for(int i = 1; i <= k; i ++){
		int num = 0; point tmp[10];
		for(int j = 0; j < 3; j ++){
			point res;
			if(line_make_point(ll, line(a[i][j], a[i][j + 1]), res) && PointOnSegment(res, a[i][j], a[i][j + 1])){
				tmp[++ num] = res;
			}
		}
		if(num) {
			long double miny = 1e9, maxy = 0;
			for(int i = 1; i <= num; i ++){
				gmin(miny, tmp[i].y);
				gmax(maxy, tmp[i].y);
			}
			tmp[1].x = mid, tmp[1].y = miny;
			tmp[2].x = mid, tmp[2].y = maxy;
			seg[++ segn].a = tmp[1], seg[segn].b = tmp[2];
			if(sgn(tmp[1].y - tmp[2].y) == 0){
				if(sgn(a[i][0].x - mid) < 0 || sgn(a[i][1].x - mid) < 0 || sgn(a[i][2].x - mid) < 0)
					larea += area(a[i][0], a[i][1], a[i][2]);
				else rarea += area(a[i][0], a[i][1], a[i][2]);
			}
			else if(sgn(a[i][0].x - mid) == 0 || sgn(a[i][1].x - mid) == 0 || sgn(a[i][2].x - mid) == 0){
				int lnum = 0, rnum = 0;
				point pl[4], pr[4];
				for(int j = 0; j < 3; j ++){
                    if(sgn(a[i][j].x - mid) < 0) pl[++ lnum] = a[i][j];
                    if(sgn(a[i][j].x - mid) > 0) pr[++ rnum] = a[i][j];
				}
				if(lnum == 1 && rnum == 1){
                    larea += area(tmp[1], tmp[2], pl[1]);
                    rarea += area(tmp[1], tmp[2], pr[1]);
				}
				else if(lnum == 1) larea += area(a[i][0], a[i][1], a[i][2]);
				else rarea += area(a[i][0], a[i][1], a[i][2]);
			}
			else{
				int lnum = 0, rnum = 0;
				point pl[4], pr[4];
				for(int j = 0; j < 3; j ++){
					if(sgn(a[i][j].x - mid) < 0) pl[++ lnum] = a[i][j];
					if(sgn(a[i][j].x - mid) > 0) pr[++ rnum] = a[i][j];
				}
				if(lnum == 1){
					long double tt = area(pl[1], tmp[1], tmp[2]);
					larea += tt;
					rarea += area(a[i][0], a[i][1], a[i][2]) - tt;
				}
				else{
					long double tt = area(pr[1], tmp[1], tmp[2]);
					rarea += tt;
					larea += area(a[i][0], a[i][1], a[i][2]) - tt;
				}
			}
		}
		else{
            if(sgn(a[i][0].x - mid) < 0) larea += area(a[i][0], a[i][1], a[i][2]);
            else rarea += area(a[i][0], a[i][1], a[i][2]);
		}
	}
	// 合併線段
	sort(seg + 1, seg + segn + 1, cmp);
	long double r = 0;
	for(int i = 1; i <= segn; i ++){
        if(i==1&&sgn(seg[i].a.y)>0){
            double xx = mid; double yy = 0;
            printf("%.8f %.8f\n", xx, yy);
            return 1;
        }
		if(sgn(seg[i].a.y - r) > 0){
            double xx = mid; double yy = (seg[i].a.y+r)/2;
            printf("%.8f %.8f\n", xx, yy);
            return 1;
		}
		r = max(r,seg[i].b.y);
	}
	if(sgn(r-m)<0){
            double xx = mid; double yy = m;
            printf("%.8f %.8f\n", xx, yy);
            return 1;
	}
	return 0;
}

int main()
{
	scanf("%d%d%d", &k, &n, &m);
	for(int i = 1; i <= k; i ++){
		for(int j = 0; j < 3; j ++){
			double xx, yy;
			scanf("%lf%lf", &xx, &yy);
            a[i][j].x = xx; a[i][j].y = yy;
		} a[i][3] = a[i][0];
	}
	long double l = 0, r = n;
	while(1){
		long double mid = (l + r) / 2;
		long double larea = 0, rarea = 0;
		if(check(mid, larea, rarea)){	// 可以的話在裡面輸出
			break;
		}
		else{
			if(larea - mid*2.0*m < -1e-6) r = mid;
			else l = mid;
		}
	}
	return 0;
}

/*
【trick&&吐槽】

5 4 3
0 0 3 0 0 2
3 3 0 1 0 3
1 1 3 1 2 3
3 0 4 0 4 3
4 3 3 2 4 1

【題意】


【分析】


【時間複雜度&&優化】


*/

  

相關文章