首页 > 其他分享 >2020-2021 ICPC East Central North America Regional Contest (ECNA 2020)

2020-2021 ICPC East Central North America Regional Contest (ECNA 2020)

时间:2024-02-03 19:55:08浏览次数:21  
标签:std Central int res back 2020 const America size

Preface

队友C麻了我直接3h下班雀魂启动,如果时间多点感觉还有AK希望

不过不得不说北美场难度都集中在模拟题上了,一般压轴都是数学或者几何,而这类题目遇到徐神祁神就是洒洒水了


A. All in the Family

出题人真是丧心病狂,不过这题只是看起来恶心实际写起来感觉还好

做法本身由于树的点数很少,找LCA什么的都可以暴力

只不过输出答案的时候要多讨论讨论,按照题目里给出的一个个判断即可

要注意的是在输出cousins关系时不要把输出的两个人搞反了,算是个很隐蔽的坑点

#include<cstdio>
#include<iostream>
#include<string>
#include<map>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int nn,mm,idx,fa[N],dep[N]; map <string,int> rst; string name[N]; vector <int> v[N];
inline void DFS(CI now)
{
	for (auto to:v[now]) dep[to]=dep[now]+1,DFS(to);
}
inline int getLCA(int x,int y)
{
	if (dep[x]<dep[y]) swap(x,y);
	while (dep[x]>dep[y]) x=fa[x];
	if (x==y) return x;
	while (x!=y) x=fa[x],y=fa[y];
	return x;
}
int main()
{
	//freopen("A.out","w",stdout);
	ios::sync_with_stdio(false); cin.tie(0);
	auto ID=[&](const string& s)
	{
		if (rst.count(s)) return rst[s];
		return rst[s]=++idx;
	};
	RI i,j; for (cin>>nn>>mm,i=1;i<=nn;++i)
	{
		string s; cin>>s; int x=ID(s),y;
		for (cin>>y,j=1;j<=y;++j)
		{
			string t; cin>>t; int z=ID(t);
			fa[z]=x; v[x].push_back(z);
		}
	}
	int rt; for (i=1;i<=idx;++i) if (!fa[i]) { rt=i; break; }
	//for (i=1;i<=idx;++i) for (auto j:v[i]) printf("%d -> %d\n",i,j);
	for (DFS(rt),i=1;i<=mm;++i)
	{
		string s,t; cin>>s>>t; int x=ID(s),y=ID(t);
		int z=getLCA(x,y),m=dep[x]-dep[z],n=dep[y]-dep[z];
		bool flag=0; if (m>n) swap(m,n),swap(x,y),swap(s,t),flag=1;
		auto trs=[&](CI x)
		{
			string s=to_string(x);
			if (x>=11&&x<=13) return s+"th";
			if (x%10==1) return s+"st";
			if (x%10==2) return s+"nd";
			if (x%10==3) return s+"rd";
			return s+"th";
		};
		if (m==0)
		{
			if (n==1) { cout<<t<<" is the child of "<<s<<endl; continue; }
			cout<<t<<" is the "; for (j=1;j<=n-2;++j) cout<<"great ";
			cout<<"grandchild of "<<s<<endl; continue;	
		}
		if (m==n)
		{
			if (n==1) cout<<s<<" and "<<t<<" are siblings"<<endl;
			else cout<<s<<" and "<<t<<" are "<<trs(n-1)<<" cousins"<<endl; continue;
		}
		if (flag) swap(s,t);
		if (n-m==1) cout<<s<<" and "<<t<<" are "<< trs(m-1)<<" cousins, 1 time removed"<<endl;
		else cout<<s<<" and "<<t<<" are "<<trs(m-1)<<" cousins, "<<n-m<<" times removed"<<endl;
	}
	return 0;
}

B. Kinky Word Searches

本来想抢这题一血的,可惜没抢到

做法很简单,直接大力DP,\(f_{i,j,x,y,d}\)表示当前匹配了\(s\)的前\(i\)个字符,转向了\(j\)次,在方格中\((x,y)\)位置,面朝的方向为\(d\)的状态是否可达

转移的时候再枚举一个方向即可,注意特判第一步的走法

#include<cstdio>
#include<iostream>
#include<cctype>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=12,dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
int n,m,t,len; char a[N][N],s[105]; bool f[105][105][N][N][8];
int main()
{
	RI i,j,k; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) for (j=1;j<=m;++j)
	{
		char ch; while (ch=getchar(),!isalpha(ch)); a[i][j]=ch;
	}
	scanf("%d%s",&t,s+1); len=strlen(s+1); t=min(len,t);
	for (i=1;i<=n;++i) for (j=1;j<=m;++j)
	if (a[i][j]==s[1]) for (k=0;k<8;++k) f[1][0][i][j][k]=1;
	for (i=1;i<len;++i) for (j=0;j<=min(t,i-1);++j)
	for (int x=1;x<=n;++x) for (int y=1;y<=m;++y) for (k=0;k<8;++k)
	if (f[i][j][x][y][k])
	{
		for (int d=0;d<8;++d)
		{
			int nx=x+dx[d],ny=y+dy[d];
			if (nx<1||nx>n||ny<1||ny>m) continue;
			if (a[nx][ny]==s[i+1]) f[i+1][j+(i!=1&&k!=d)][nx][ny][d]=1;
		}
	}
	bool flag=0; for (i=1;i<=n;++i) for (j=1;j<=m;++j)
	for (k=0;k<8;++k) flag|=f[len][t][i][j][k];
	return puts(flag?"YES":"NO"),0;
}

C. Math Trade

祁神开场写的签到

#include<bits/stdc++.h>
using namespace std;

const int N = 105;
int n;
vector<int> G[N];
map<string, int> mp; int idx=0;
int ans=0;
bool vis[N];

void dfs(int x, int dep){
	vis[x]=true;
	for (int v : G[x]){
		if (vis[v]) ans = max(ans, dep);
		else dfs(v, dep+1);
	}
}

signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> n;
	for (int i=1; i<=n; ++i){
		int a, b;
		string str;
		cin >> str;
		cin >> str; if (!mp.count(str)) mp[str] = ++idx; a=mp[str];
		cin >> str; if (!mp.count(str)) mp[str] = ++idx; b=mp[str];
		G[a].push_back(b);
	}	
	for (int i=1; i<=n; ++i){
		if (!vis[i]) dfs(i, 1);	
	}
	
	if (ans>0) cout << ans << '\n';
	else cout << "No trades possible\n";
	return 0;	
}

D. Oreperations Research

大暴力题,敢写敢过

注意到有效的状态数很少,当前火车的车厢号,A/B开头的位置即可唯一确定一个状态,这样是\(O(nrs)\)的

转移不妨再\(O(rs)\)大力枚举A/B向后转移的状态,剩下的部分就是用若干个A的和以及B的和来凑

直接预处理个完全背包把所有有解的数求出来即可,套个bitset优化硬艹\(2\times 10^6\)也不是不行

#include <bits/stdc++.h>

int r, s, n;

int a[100], b[100], c[100], as, bs;

bool dp[100][50][50];
std::bitset<2000001> hkr;

int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin >> r >> s >> n;
    for(int i = 0; i < r; ++i) std::cin >> a[i], a[i + r] = a[i];
    for(int i = 0; i < s; ++i) std::cin >> b[i], b[i + s] = b[i];
    for(int i = 0; i < n; ++i) std::cin >> c[i];
    for(int i = 1; i < 2 * r; ++i) a[i] += a[i - 1];
    for(int i = 1; i < 2 * s; ++i) b[i] += b[i - 1];
    as = a[r - 1], bs = b[s - 1];
    hkr[0] = true;
    for(int i = 1; i <= 2000000; ++i) {
        if(i >= as) hkr[i] = hkr[i] || hkr[i - as];
        if(i >= bs) hkr[i] = hkr[i] || hkr[i - bs];
    }
    // std::cerr << "as = " << as << ", bs = " << bs << char(10);
    dp[0][0][0] = true;
    for(int i = 0; i < n; ++i) for(int j = 0; j < r; ++j) for(int k = 0; k < s; ++k) if(dp[i][j][k]) {
        // std::cerr << "dp[" << i << "][" << j << "][" << k << "] == true\n";
        for(int l = j; l < j + r; ++l) for(int m = k; m < k + s; ++m) {
            int cargo = c[i];
            if(l) cargo -= a[l - 1]; if(m) cargo -= b[m - 1];
            if(j) cargo += a[j - 1]; if(k) cargo += b[k - 1];
            // std::cerr << "cargo[" << l << "][" << m << "] = " << cargo << ", c[" << i << "] = " << c[i] << char(10);
            if(cargo < 0 || !hkr[cargo]) continue;
            if(i + 1 == n) return std::cout << "yes" << std::endl, 0;
            int x = l, y = m;
            if(x >= r) x -= r; if(y >= s) y -= s;
            dp[i + 1][x][y] = true;
        }
    }
    std::cout << "no" << std::endl;
    return 0;
}

E. Over the Hill, Part 1

Easy Version没啥好说的,模拟就完事了

#include <bits/stdc++.h>

constexpr int mod = 37;

struct mat: public std::vector<std::vector<int>> {
    mat(size_t n): vector(n, std::vector<int>(n, 0)) {}
    mat operator *(const mat &b) const {
        const size_t n = this->size();
        mat res(n);
        for(size_t i = 0; i < n; ++i) {
            for(size_t j = 0; j < n; ++j) {
                for(size_t k = 0; k < n; ++k)
                    res[i][j] += (*this)[i][k] * b[k][j];
                res[i][j] %= mod;
            }
        }
        return res;
    }
};

std::vector<int> decode(const std::string &s, size_t n) {
    std::vector<int> res;
    res.reserve(s.size());
    for(char c: s) {
        if(std::isupper(c)) res.push_back(c - 'A');      else
        if(std::isdigit(c)) res.push_back(c - '0' + 26); else
                            res.push_back(36);
    }
    while(res.size() % n) res.push_back(36);
    return res;
}

std::string encode(const std::vector<int> &s, size_t n) {
    std::string res;
    res.reserve(s.size());
    for(int c: s) {
        if(c < 26) res.push_back(c + 'A');      else
        if(c < 36) res.push_back(c - 26 + '0'); else
                   res.push_back(' ');
    }
    while(res.size() && res.back() == ' ') res.pop_back();
    return res;
}

int main(void) {
    size_t n; std::cin >> n;
    mat a(n); for(auto &a: a) for(auto &a: a) std::cin >> a;
    std::string s; while(s.size() == 0) std::getline(std::cin, s);
    std::vector<int> t = decode(s, n);
    std::vector<int> h;
    for(size_t i = 0; i < t.size(); i += n) {
        h.assign(n, 0);
        // for(int j = 0; j < n; ++j) std::cerr << t[i + j] << char(j == n - 1 ? 10 : 32);
        for(size_t j = 0; j < n; ++j) {
            for(size_t k = 0; k < n; ++k)
                h[j] += a[j][k] * t[i + k];
            h[j] %= mod;
        }
        // for(int j = 0; j < n; ++j) std::cerr << h[j] << char(j == n - 1 ? 10 : 32);
        for(size_t j = 0; j < n; ++j) t[i + j] = h[j];
    }
    std::cout << encode(t, n) << std::endl;
    return 0;
}

F. Over the Hill, Part 2

手玩下会发现这玩意就等价于一个矩阵求逆,直接上模意义下的高斯消元板子即可

因为上次我写高消被腐乳的前车之鉴,决定以后都把高消扔给徐神来写了(逃

注意这题对输入的转化比较恶心,同时无解和多解的判断也要留心

#include <bits/stdc++.h>

constexpr int mod = 37;

constexpr std::array<int, 37> inv = ([]() {
    std::array<int, 37> inv;
    inv[0] = 0;
    for(int i = 1; i < 37; ++i) {
        inv[i] = 1;
        for(int j = 1; j <= 35; ++j) inv[i] = inv[i] * i % mod;
    }
    return inv;
})();

struct vivi: public std::vector<int> {
    vivi (size_t s = 0): vector(s, 0) {}
    vivi& operator +=(const vivi &b) {
        for(size_t i = 0; i < size(); ++i) (*this)[i] = ((*this)[i] + b[i]) % mod;
        return *this;
    }
    vivi& operator -=(const vivi &b) {
        for(size_t i = 0; i < size(); ++i) (*this)[i] = ((*this)[i] - b[i] + mod) % mod;
        return *this;
    }

    vivi& operator *=(int p) {
        for(size_t i = 0; i < size(); ++i) (*this)[i] = (*this)[i] * p % mod;
        return *this;
    }
    vivi operator *(int p) const {
        vivi c(size());
        for(size_t i = 0; i < size(); ++i) c[i] = (*this)[i] * p % mod;
        return c;
    }
};

std::vector<int> decode(const std::string &s, size_t n) {
    std::vector<int> res;
    res.reserve(s.size());
    for(char c: s) {
        if(std::isupper(c)) res.push_back(c - 'A');      else
        if(std::isdigit(c)) res.push_back(c - '0' + 26); else
                            res.push_back(36);
    }
    while(res.size() % n) res.push_back(36);
    return res;
}

std::string encode(const std::vector<int> &s, size_t n) {
    std::string res;
    res.reserve(s.size());
    for(int c: s) {
        if(c < 26) res.push_back(c + 'A');      else
        if(c < 36) res.push_back(c - 26 + '0'); else
                   res.push_back(' ');
    }
    while(res.size() && res.back() == ' ') res.pop_back();
    return res;
}

void guass(std::vector<vivi> &a) {
    const int n = a.size(), m = a.front().size();
    int hkr = 0;
    for(int i = 0; i < m && hkr < n; ++i) {
        int ars = hkr;
        while(ars < n && a[ars][i] == 0) ars += 1;
        if(ars == n) continue;
        if(hkr != ars) std::swap(a[ars], a[hkr]);

        a[hkr] *= inv[a[hkr][i]];

        for(int j = 0; j < n; ++j) if(j != hkr && a[j][i])
            a[j] -= a[hkr] * a[j][i];
        
        hkr += 1;
    }
    return ;
}

template<typename It>
bool my_any(It begin, It end) {
    while(begin != end) {
        if(*begin) return true;
        begin ++;
    }
    return false;
}

int main(void) {
    size_t n; std::cin >> n;
    std::vector<int> a, b; {
        std::string as, bs;
        while(as.size() == 0) std::getline(std::cin, as);
        while(bs.size() == 0) std::getline(std::cin, bs);
        a = decode(as, n), b = decode(bs, n); 
    }
    int l = a.size();
    std::vector<vivi> mat(l / n);
    for(int i = 0; i < l; i += n) {
        vivi lv(2 * n);
        for(int j = 0; j < n; ++j) lv[j] = a[i + j], lv[n + j] = b[i + j];
        mat[i / n] = std::move(lv);
    }
    // for(int i = 0; i < mat.size(); ++i) for(int j = 0; j < mat[i].size(); ++j)
    //     std::cerr << mat[i][j] << char(j == mat[i].size() - 1 ? 10 : 32);
    guass(mat);
    // for(int i = 0; i < mat.size(); ++i) for(int j = 0; j < mat[i].size(); ++j)
    //     std::cerr << mat[i][j] << char(j == mat[i].size() - 1 ? 10 : 32);
    int m = l / n;

    for(int i = 0; i < m; ++i) {
        bool flag_l = false, flag_r = false;
        for(int j = 0; j < n    ; ++j) if(mat[i][j]) { flag_l = true; break; }
        for(int j = n; j < 2 * n; ++j) if(mat[i][j]) { flag_r = true; break; }
        if(!flag_l && flag_r) return std::cout << "No solution\n", 0;
    }

    if(m < n) return std::cout << "Too many solutions\n", 0;
    for(int i = 0; i < n; ++i) if(mat[i][i] != 1)
        return std::cout << "Too many solutions\n", 0;
    for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j)
        std::cout << mat[j][i + n] << char(j == n - 1 ? 10 : 32); 
    return 0;
}

G. A Rank Problem

签到,模拟一下即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int n,m,x,y,a[N];
int main()
{
	RI i; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) a[i]=i; getchar();
	while (m--)
	{
		scanf("T%d T%d",&x,&y); getchar();
		auto find=[&](CI x)
		{
			for (RI i=1;i<=n;++i) if (a[i]==x) return i;
		};
		int px=find(x),py=find(y);
		if (px>py)
		{
			for (i=py;i<px;++i) a[i]=a[i+1]; a[px]=y;
		}
	}
	for (i=1;i<=n;++i) printf("T%d ",a[i]);
	return 0;
}

H. Restroom Monitor

徐神开场一眼秒的一个贪心,我题目都没看

#include <bits/stdc++.h>

int main() {
    std::ios::sync_with_stdio(false);
    int s, n; std::cin >> s >> n;
    std::vector<int> a, b;
    for(int i = 1; i <= n; ++i) {
        int d; std::string type;
        std::cin >> d >> type;
        (type[0] == 'y' ? a : b).push_back(d);
    }
    std::sort(a.begin(), a.end());
    std::sort(b.begin(), b.end());
    std::set<int> ocy;
    
    int S = (int)2e9;
    for(auto i = a.rbegin(); i != a.rend(); ++i) {
        if(*i < S) {
            ocy.insert(*i);
            S = *i - 1;
        } else {
            ocy.insert(S--);
        }
    }

    if(ocy.size() && *(ocy.begin()) <= 0) return std::cout << "no\n", 0;
    
    // for(auto o: ocy) std::cerr << o << " "; std::cerr << char(10);

    int cur = 0, siz = 0;
    for(auto d: b) {
        while(siz == 0) siz = s - (ocy.find(++cur) != ocy.end());
        if(cur > d) return std::cout << "no\n", 0;
        siz -= 1;
    }

    std::cout << "yes\n";
    return 0;
}

I. Scholar's Lawn

压轴几何,但是被祁神一眼秒了

大力找出所有实线和虚线的交点,将这些点作为关键点跑最短路即可

最后祁神差一点就在比赛结束前Rush出来了,有点可惜

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ft first
#define sd second

using LD = long double;
const LD eps = 1e-8;
const LD INF = 1e18;
int sgn(LD x){return fabs(x)<=eps ? 0 : (x>eps ? 1 : -1);}

struct Pt{
	LD x, y;
	LD crs(Pt b)const{return x*b.y-y*b.x;}
	LD dot(Pt b)const{return x*b.x+y*b.y;}
	Pt operator-(Pt b)const{return Pt{x-b.x, y-b.y};}
	Pt operator+(Pt b)const{return Pt{x+b.x, y+b.y};}
	Pt operator*(LD b)const{return Pt{x*b, y*b};}
	bool operator<(Pt b)const{return sgn(x-b.x)!=0 ? sgn(x-b.x)<0 : sgn(y-b.y)<0;}
	bool operator==(Pt b)const{return sgn(x-b.x)==0 && sgn(y-b.y)==0;}
	LD len(){return sqrtl(x*x+y*y);}
};
int tcross(Pt p, Pt a, Pt b){return sgn((a-p).crs(b-p));}


Pt pt_l_l(Pt p1, Pt v1, Pt p2, Pt v2){ return p1 + v1 * (v2.crs(p1-p2)/v1.crs(v2));}

bool segins(Pt a, Pt b, Pt c, Pt d, Pt &res){
	int sg1=tcross(a, b, c);
	int sg2=tcross(a, b, d);
	int sg3=tcross(c, d, a);
	int sg4=tcross(c, d, b);
	if (0==sg1 && 0==sg2) return false;
	
	if (sg1*sg2<=0 && sg3*sg4<=0){
		res = pt_l_l(a, b-a, c, d-c);
		return true;
	}else return false;
}

const int N = 1e6+5;
int n;
struct Edge{int v; LD w;};
vector<Edge> G[N];
vector<vector<int>> seg;
vector<Pt> vec; int idx=-1;
Pt S; LD vs;
pair<Pt, Pt> F; LD vf;
vector<pair<int, LD>> goal;

struct Node{
	int x; LD d;
	bool operator<(Node b)const{return sgn(d-b.d)>0;}
};
bool inD[N];
LD dis[N];

void addEdge(int a, int b, LD w){
//	printf("addEdge(%lld %lld %Lf)\n", a, b, w);
	G[a].push_back(Edge{b, w});
	G[b].push_back(Edge{a, w});
}

signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cout << setiosflags(ios::fixed) << setprecision(10);
	cin >> n;
	for (int i=1; i<=n; ++i){
		Pt a, b; cin >> a.x >> a.y >> b.x >> b.y;
		int at = ++idx; vec.push_back(a);
		int bt = ++idx; vec.push_back(b);
		seg.push_back(vector<int>{at, bt});
	}
	cin >> S.x >> S.y >> vs;
	cin >> F.ft.x >> F.ft.y >> F.sd.x >> F.sd.y >> vf;
	
	int St = ++idx; vec.push_back(S);
	int sz = seg.size();
	
	for (int i=0; i<sz; ++i){
		int a=seg[i][0], b=seg[i][1];
//		printf("i=%lld %Lf %Lf %Lf\n", i, (vec[b]-vec[a]).crs(S-vec[a]), (vec[b]-vec[a]).dot(S-vec[a]), (vec[a]-vec[b]).dot(S-vec[b]));
		if (tcross(vec[a], vec[b], S)==0 && sgn((vec[b]-vec[a]).dot(S-vec[a]))>=0 && sgn((vec[a]-vec[b]).dot(S-vec[b]))>=0){
			seg[i].push_back(St);
//			printf("St=%lld on seg %lld\n", St, i);
		}
	}
	for (int i=0; i<sz; ++i){
		for (int j=i+1; j<sz; ++j){
			int a=seg[i][0], b=seg[i][1];
			int c=seg[j][0], d=seg[j][1];
			Pt res;
			if (segins(vec[a], vec[b], vec[c], vec[d], res)){
//				printf("i=%lld j=%lld res(%Lf %Lf)\n", i, j, res.x, res.y);
				int rt = ++idx; vec.push_back(res);
				seg[i].push_back(rt);
				seg[j].push_back(rt);
			}
		}
	}
	for (int i=0; i<sz; ++i){
		int a=seg[i][0], b=seg[i][1];
		Pt res;
		if (segins(F.ft, F.sd, vec[a], vec[b], res)){
//			printf("i=%lld res(%Lf %Lf)\n", i, res.x, res.y);
			int rt = ++idx; vec.push_back(res);
			seg[i].push_back(rt);
			goal.push_back(make_pair(rt, (res-F.ft).len()/vf));
		}	
	}
//	for (int i=0; i<=idx; ++i) printf("%lld : (%Lf %Lf)\n", i, vec[i].x, vec[i].y);
	
	for (auto vp : seg){
		sort(vp.begin(), vp.end(), [&](int a, int b){return vec[a]<vec[b];});
		int szp = vp.size();
		for (int i=1; i<szp; ++i) addEdge(vp[i-1], vp[i], (vec[vp[i-1]]-vec[vp[i]]).len()/vs);
	}
	
	for (int i=0; i<=idx; ++i) dis[i]=INF;
	priority_queue<Node> Q;
	Q.push(Node{St, 0.0L});
	dis[St]=0.0L;
	while (!Q.empty()){
		auto [x, _] = Q.top(); Q.pop();
		if (inD[x]) continue; inD[x]=true;
		for (auto [v, w] : G[x]){
			if (sgn(dis[x]+w - dis[v])<0){
				dis[v] = dis[x]+w;
				Q.push(Node{v, dis[v]});
			}
		}
	}
//	for (int i=0; i<=idx; ++i) printf("dis[%lld]=%Lf\n", i, dis[i]);
	
	LD ans = INF;
	for (auto [id, tim] : goal){
		if (sgn(tim-dis[id])>=0){
			ans = min(ans, tim);
		}
	}
	
	if (sgn(INF-ans)>0) cout << ans << '\n';
	else cout << "-1\n";
	
	return 0;	
}


J. Simply Sudoku

没啥好多的,又是大力模拟题,直接把题目中两种操作实现一个个试就完了

#include<bits/stdc++.h>
using namespace std;

int A[9][9];
bool tbl[9][9][9];

void upd(int x, int y, int c){
	for (int i=0; i<9; ++i) tbl[i][y][c]=false;	
	for (int i=0; i<9; ++i) tbl[x][i][c]=false;
	for (int i=0; i<3; ++i) for (int j=0; j<3; ++j) tbl[x/3*3+i][y/3*3+j][c]=false;
	for (int k=0; k<9; ++k) tbl[x][y][k]=false;
	tbl[x][y][c]=true;
}

signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	
	for (int i=0; i<9; ++i) for (int j=0; j<9; ++j) for (int k=0; k<9; ++k) tbl[i][j][k]=true;
	for (int i=0; i<9; ++i) for (int j=0; j<9; ++j){
		cin >> A[i][j]; --A[i][j];
		if (A[i][j]>=0) upd(i, j, A[i][j]);
	}
	bool ok=true;
	while (ok){
		ok=false;
		for (int i=0; i<9; ++i) for (int j=0; j<9; ++j) if (-1==A[i][j]){
			int cnt=0, val=-1;
			for (int k=0; k<9; ++k) if (tbl[i][j][k]) ++cnt, val=k;
			if (1==cnt){ok=true; upd(i, j, val); A[i][j]=val;}
			else{
				for (int k=0; k<9; ++k) if (tbl[i][j][k]){
					bool flag=true;
					for (int p=0; p<9; ++p) if (p!=i && tbl[p][j][k]) flag=false;
					if (flag){ok=true; upd(i, j, k); A[i][j]=k;}
					
					flag=true;
					for (int p=0; p<9; ++p) if (p!=j && tbl[i][p][k]) flag=false;
					if (flag){ok=true; upd(i, j, k); A[i][j]=k;}
					
					flag=true;
					for (int p=0; p<3; ++p) for (int q=0; q<3; ++q){
						if (!(i/3*3+p==i && j/3*3+q==j) && tbl[i/3*3+p][j/3*3+q][k]) flag=false;
					}
					if (flag){ok=true; upd(i, j, k); A[i][j]=k;}
				}
			}
//			printf("A[%d][%d]=%d cnt=%d val=%d\n", i, j, A[i][j], cnt, val);
		}
	}
	
	ok=true;
	for (int i=0; i<9; ++i) for (int j=0; j<9; ++j) if (-1==A[i][j]) ok=false;
	cout << (ok ? "Easy\n" : "Not easy\n");
	for (int i=0; i<9; ++i){
		for (int j=0; j<9; ++j){
			if (-1==A[i][j]) cout << ". ";
			else cout << A[i][j]+1 << ' ';
		}cout << '\n';
	}
	
	return 0;	
}

K. Weighty Tomes

很经典的问题,这个题的一个等价版本就是扔鸡蛋问题,因此做的时候就以这个为参考

不难想到设状态\(f_{i,j}\)表示要在\(i\)层楼中,用\(j\)个鸡蛋确定答案需要的至少步数

转移就是大力枚举当前局面下第一次投鸡蛋的楼层\(k\),则有

\[f_{i,j}=\min_\limits{1\le k\le i} [\max(f_{k-1,j-1},f_{i-k,j})+1] \]

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=5005,INF=1e9;
int n,m,f[N][25];
inline int DP(CI x,CI y)
{
	if (y==0) return x==0?0:INF;
	if (y==1) return x; if (x<=1) return x;
	if (~f[x][y]) return f[x][y];
	int ret=INF; for (RI i=1;i<=x;++i)
	ret=min(ret,max(DP(i-1,y-1),DP(x-i,y))+1);
	return f[x][y]=ret;
}
int main()
{
	scanf("%d%d",&n,&m); memset(f,-1,sizeof(f));
	int ans=DP(n,m),l=INF,r=-INF; printf("%d ",ans);
	for (RI i=1;i<=n;++i) if (max(DP(i-1,m-1),DP(n-i,m))+1==ans) l=min(l,i),r=max(r,i);
	if (l==r) printf("%d ",l); else printf("%d-%d",l,r);
	return 0;
}

L. Workers of the World Unite! Just Not Too Close.

怎么和昨天打的北美场一样是个一眼的二分图带权匹配的题啊

不难发现最后使用的门一定是一段前缀用A,然后剩下的一段后缀用B,那么我们可以直接大力枚举分界点

此时问题转化为工人——门,门——工位的多重匹配问题,由于两边都是完全图且不会相互影响,因此可以独立求解

使用KM求解二分图最小完美匹配,总复杂度\(O(n^4)\)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=55,INF=1e9;
int n,d1[N][N][2],d2[N][N][2];
struct KM
{
	int w[N][N],kx[N],ky[N],py[N],vy[N],slk[N],pre[N];
	inline int solve(CI n)
	{
		RI i,j,k; for (i=1;i<=n;++i) ky[i]=py[i]=0;
		for (i=1;i<=n;++i) for (j=1;j<=n;++j) kx[i]=max(kx[i],w[i][j]);
		for (i=1;i<=n;++i)
		{
			for (j=0;j<=n;++j) vy[j]=pre[j]=0,slk[j]=INF;
			int k=0,p=-1; for (py[k=0]=i;py[k];k=p)
			{
				int d=INF; vy[k]=1; int x=py[k];
				for (j=1;j<=n;++j) if (!vy[j])
				{
					int t=kx[x]+ky[j]-w[x][j];
					if (t<slk[j]) slk[j]=t,pre[j]=k;
					if (slk[j]<d) d=slk[j],p=j;
				}
				for (j=0;j<=n;++j)
				if (vy[j]) kx[py[j]]-=d,ky[j]+=d; else slk[j]-=d;
			}
			for (;k;k=pre[k]) py[k]=py[pre[k]];
		}
		int ret=0; for (i=1;i<=n;++i) ret+=kx[i]+ky[i];
		return -ret;
	}
}G1,G2;
inline int solve(CI x)
{
	RI i,j; for (j=1;j<=n;++j) for (i=1;i<=n;++i) G1.w[j][i]=-d1[i][j][j>x];
	for (i=1;i<=n;++i) for (j=1;j<=n;++j) G2.w[i][j]=-d2[i][j][j>x];
	return G1.solve(n)+G2.solve(n);
}
int main()
{
	RI i,j,k; for (scanf("%d",&n),i=1;i<=n;++i)
	for (j=1;j<=n;++j) for (k=0;k<2;++k) scanf("%d",&d1[i][j][k]);
	for (i=1;i<=n;++i) for (j=1;j<=n;++j) for (k=0;k<2;++k) scanf("%d",&d2[i][j][k]);
	int ans=INF,pos; for (i=0;i<=n;++i)
	{
		int tmp=solve(i); if (tmp<ans) ans=tmp,pos=i;
	}
	for (printf("%d\n",ans),solve(pos),i=1;i<=n;++i)
	printf("%d %d%c %d\n",i,G1.py[i],G1.py[i]<=pos?'A':'B',G2.py[G1.py[i]]);
	return 0;
}

Postscript

北美场题又少又简单,每天早早下班真是美滋滋

标签:std,Central,int,res,back,2020,const,America,size
From: https://www.cnblogs.com/cjjsb/p/18005120

相关文章

  • [BSidesCF 2020]Had a bad day
    [BSidesCF2020]Hadabadday打开网站有两个按钮,点击之后链接后都会加上?category=meowers猜测有文件包含漏洞,尝试?category=php://filter/read=convert.base64-encode/resource=index.php警告中看到.php出现了两次,推测源码中存在.php拼接,于是去掉.php得到PHP源码<?p......
  • 2022-2023 ICPC East Central North America Regional Contest (ECNA 2022)
    Preface闲了两天没训练,今天又开始上班,结果唐得发昏后期也没题可写直接光速下班只能说感觉老外的题目难度跨度都好大,easy确实简单,hard确实难,medium确实少A.A-MazingPuzzle题目看起来很复杂,但仔细一想会发现有用的状态总数只有\(4n^2\)种即我们可以暴力记录下两个机器人的坐......
  • [BJDCTF2020]The mystery of ip
    [BJDCTF2020]Themysteryofiphint页面的源代码里发现提示应该是和IP相关,有可能用到XFF请求头,遂用BP抓包修改了XFF之后,被成功执行,XFF可控,代码是php代码,推测:PHP可能存在Twig模版注入漏洞Smarty模板的SSTI漏洞(主要为Flask存在Jinjia2模版注入漏洞)添加模板算式,{{7*7}}成......
  • [JOISC2020] 扫除
    现在Bitaro准备用扫帚打扫房间。我们认为扫帚是放置在房间里的一条线段,并且将这条线段的长度称为扫帚的宽度。由于Bitaro很有条理,所以他只会用以下的两种方式打扫房间:Bitaro将扫帚平行于\(y\)轴放置,一端位于原点。然后他会垂直向右移动扫帚,直到不能移动为止。如果扫帚的......
  • HF2020A多功能移动照明系统
    适用范围广泛适用于铁路、水利、电网等抢险救援现场大范围移动照明。结构特性灯具体积小、重量轻,可以实现拖行、手提、背行三种携带方式。灯具底部也可以安装铁轨轮,便于用户在铁轨上作业。 灯头组件由左右两个灯头组成,采用高光效LED光源,照明亮度高,覆盖范围大,使用寿命长;灯头可折叠......
  • ATtokiomarine2020E O(rand) 题解
    题目链接点击打开链接题目解法首先,\(S\)一定要是\(T\)的子集先筛出符合条件的\(a_i\),即满足\(S\subseteqa_i\subseteqT\)令\(dif\)为\(T-S\),定义数\(x\)覆盖第\(y\)位为二进制下\(x\)的第\(y\)位为\(1\)现在的问题变成了找到大小\(\lek\)的\(\{a_i\}......
  • 2019-2020 ICPC Southwestern European Regional Programming Contest (SWERC 2019-20
    Preface这场总体打的不错,虽然最后RushL题失败,没有想到关键优化导致没卡过去有点可惜,但奈何徐神还是太C了最后10题下班,赛后祁神发现L关键优化10min改完就过了,同时赛中徐神也看出了E的做法,感觉这场时间充足甚至有AK的可能的说A.Environment-FriendlyTravel很典的一个题,不难......
  • Central Collector Installation · glowroot/glowroot Wiki
    *[glowrootjava简单的轻量的apm工具-荣锋亮-博客园](https://www.cnblogs.com/rongfengliang/p/16230407.html)*[CentralCollectorInstallation·glowroot/glowrootWiki·GitHub](https://github.com/glowroot/glowroot/wiki/Central-Collector-Installation#opt......
  • 2020-2021 ICPC Southwestern European Regional Contest (SWERC 2020)
    Preface经典前期天胡开局,70min的时候就已经过6题+会另外3题了,本来以为又要像昨天那样提前下班了后面好家伙FGH连着卡,最后磕磕碰碰刚好在结束前写完10个题,强行续上班时长了属于是A.Gratitude签到,注意出现次数相同的字符串的处理#include<cstdio>#include<iostream>#includ......
  • 2020-2021 ICPC NERC (NEERC), North-Western Russia Regional Contest (Northern Sub
    Preface最近事情挺多积压了三天没训练,本来计划着去补CF的题,但后面还是溜去写WA2杂谈了今天重归训练结果碰上超级毒瘤场,2h30min9题后剩下题目都难得飞起,最后还是靠徐神大力切了L题(我早就提前下班了)评价是这就是Russia场的威力吗,后面的Hard题是一点不可做啊A.Archivist纯签到......