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


    A. Advertising Strategy

    最优策略一定是第一天用$y$元,最后一天再用$x-y$元补满。

    枚举所有可能的$y$,然后模拟即可,天数为$O(log n)$级别。

    时间复杂度$O(xlog 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
    ",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
    ",ans/2);
    			}else{
    				printf("-%llu
    ",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
    ", 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
    ",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
    ", 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
    ", top, bot);
    		//
    	}
    	//
    	//printf("TOP = %lld, BOT = %lld
    ", 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(nlog nlog 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
    ", 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
    ", 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
    ", 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
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

  • 相关阅读:
    jQuery 集合 搜索操作(父辈元素搜索、同辈元素搜索、子元素搜索)
    struts <s:form action=""> 和 <s:submit action=""> 的区别
    654. 最大二叉树
    701. 二叉搜索树中的插入操作
    617. 合并二叉树
    98. 验证二叉搜索树
    236. 二叉树的最近公共祖先
    700. 二叉搜索树中的搜索
    235. 二叉搜索树的最近公共祖先
    105. 从前序与中序遍历序列构造二叉树
  • 原文地址:https://www.cnblogs.com/clrs97/p/7901099.html
Copyright © 2020-2023  润新知