Codeforces Round #639 (Div. 2) 补题


A. Puzzle Pieces
首先只有一行或只有一列是可以拼出来的。之后可以猜出剩下的情况只有2x2可以,拼图只有一条边凹进去,构造过程中不难发现这一点。比较简单的写法是判断m+n>=mn

代码

#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
#define x first
#define y second
typedef long long int ll;
using namespace std;
const int mod = 1000000007;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif   
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        if(n == 1 || m == 1) cout<<"YES\n";
        else if(n == 2 && m == 2) cout<<"YES\n";
        else cout<<"NO\n";
    }
 	return 0;
}
 
 

B. Card Constructions
我的做法是先写求出数列的通项,然后就能根据n得出不超过n的最大项数r,之后从r向下枚举,遇到n大于a[r]时,n就减去a[r],直到n变成0。

代码

#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
const int mod = 1000000007;
 
vector<int> a;
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif   
    int t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        int ans = 0;
        ll l=0,r=100000;
        while(r-l>1){
            ll mid=(l+r)/2;
            if((3*mid*mid+mid)/2 > n) r=mid;
            else l=mid;
        }
        for(ll i=l;;i--){
            if(n<2) break;
            ll p=(3*i*i+i)/2;
            while(n>=p){
			
                n -= p;
                ans++;
            }
        }
        cout<<ans<<endl;
    }
 	return 0;
}
 

C. Hilbert's Hotel
这个题的题意花了好久才弄明白:旅馆里给每个非负整数都准备了一个房间,现在需要安排这些房间,有n个编号a[i],第k个整数安排到第k+a[k%n]个房间,问是不是会有两个数在一个房间。先考虑前k在[0,n-1]的情况,第i个数到房间i+a[i%n],那么第i+pn个数就会到房间pn+i+a[i%n],只要i+a[i%n]在模n的意义下互不相同,所有整数的安排就不会冲突。

代码

#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
const int mod = 1000000007;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
vector<int> a;
map<int, bool> vis;
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif   
    int t;
    cin>>t;
    while(t--){
        int n;
        cin >> n;
        a.resize(n);
        vis.clear();
        for(auto &x:a) cin>>x;
        bool flag = true;
        for(int i=0;i<n;i++){
            int p = i + a[i%n];
            p = (p % n + n) % n;
            if(!vis[p]){
                vis[p] = 1;
            }
            else{
                flag = false;
                break;
            }
        }
        if(flag) cout<<"YES\n";
        else cout<<"NO\n";
    }
 	return 0;
}


D. Monopole Magnets
我是先想到如果一个黑色区域可以通过放S满足题意,那么这个区域放满S也是可行的(可以画图试一下),这样只需要在这个黑色区域放一个N就可以,所以一个样例如果有解的话,答案就是图中黑色联通块的数量。之后考虑什么时候无解
1.因为每个黑色块里都有S,那么就不能存在某一行或某一列中存在两边是黑色中间是白色的情况,否则N就会从某一边的黑色沿着白色被吸到另一边的白色部分。
2.题中要求每一行每一列都要有S,如果某一行或某一列已经有黑块了,那么根据上面的构造就会有S。如果某一行没有黑块,但是图中每一列都有黑块,那么这一行就没法放S,否则这一行放S的那一列就会吸引同一列的黑色块中的N。

代码
#pragma GCC optimize(2)
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#include<utility>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
const int mod = 1000000007;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int n,m;
int a[1005][1005];
bool vis[1005][1005];
bool r[1005], c[1005];
queue<int> q;
int ans;
int mx[4]={0,0,1,-1},my[4]={1,-1,0,0};
void bfs(int x, int y){
    q = queue<int>();
    q.push(x),q.push(y);
    vis[x][y]=1;
    while(!q.empty()){
        int xx=q.front();
        q.pop();
        int yy=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int tx = xx + mx[i];
            int ty = yy + my[i];
            if(vis[tx][ty]||!a[tx][ty]) continue;
            if(xx<1||xx>n||yy<1||yy>m) continue;
            vis[tx][ty]=1;
            q.push(tx);
            q.push(ty);
        }
    }
}
int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif   
   
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            char v;
            cin>>v;
            if(v=='#') {
                a[i][j] = 1;
                r[i] = 1;
                c[j] = 1;
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!vis[i][j]&&a[i][j]){
                bfs(i, j);
                ans++;//cout<<i<<" "<<j<<endl;
            }
        }
    }
    bool ok = true;
    for(int i=1;i<=n;i++){
        if(!r[i]){
            int num = 0;
            for(int j=1;j<=m;j++){
                if(c[j]) num++;
            }
            if(num == m){
                ok = false;
                break;
            }
        }
    }
    if(!ok){
        cout<<-1;
        return 0;
    }

    for(int j=1;j<=m;j++){
        if(!c[j]){
            int num = 0;
            for(int i=1;i<=n;i++){
                if(r[i]) num++;
            }
            if(num == n){
                ok = false;
                break;
            }
        }
    }
    if(!ok){
        cout<<-1;
        return 0;
    }

    for(int i=1;i<=n;i++){
        int num = 0;
        for(int j=1;j<=m;j++) if(a[i][j]) num++;
        int t = 0;
        for(int j=1;j<=m;j++){
            if(a[i][j]) t++;
            else{
                if(a[i][j-1]&&t<num){
                    ok = false;
                    break;
                }
            }
        }
        if(!ok) break;
    }
    if(!ok){
        cout<<-1;
        return 0;
    }
    for(int j=1;j<=m;j++){
        int num = 0;
        for(int i=1;i<=n;i++) if(a[i][j]) num++;
        int t = 0;
        for(int i=1;i<=m;i++){
            if(a[i][j]) t++;
            else{
                if(a[i-1][j]&&t<num){
                    ok = false;
                    break;
                }
            }
        }
        if(!ok) break;
    }
    if(!ok){
        cout<<-1;
        return 0;
    }
    cout<<ans;
 	return 0;
}

E. Quantifier Question
根据每组数的大小关系建立有向边,要成立的话图中就不能有环,否则一定有解,所以先判断一下是否有环。
判断完是否有解之后,第i个数前的符号选取取决于是否已经有大小关系对他进行了约束,比如说有关系1<2,2<3,在选取1的符号时,2,3的符号还没选,不对1构成约束,所以1之前的符号选∀,但在选取2的符号时,已经选定了1,所以2的符号就不能选∀。因为Q1,Q2...的选取是按顺序来的,所以在选取Qi的符号时看一下他的前置点和后置点是否已经选过(序号小于他),没有的话就选∀

代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
const int mod = 1000000007;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}

int n, m, cnt, temp;
vector<int> bfor[200005], lst[200005];
int in_degree[200005], l[200005], pre[200005], ans[200005];
bool  vis[200005];

bool topo_sort(){
    queue<int> q;
    for(int i=1;i<=n;i++){
        if(!in_degree[i]){
            q.push(i);
            ++cnt;
        }
    }
    while(!q.empty()){
        int u = q.front();
        q.pop();
        for(auto x:lst[u]){
            in_degree[x]--;
            if(!in_degree[x]){
                q.push(x);
                ++cnt;
            }
        }
    }
    return cnt == n;
}

void dfs1(int u){
    l[u] = u;
    for(auto x:lst[u]){
        if(!l[x]) dfs1(x);
        l[u] = min(l[u], l[x]);
    }
}

void dfs2(int u){
    pre[u] = u;
    for(auto x:bfor[u]){
        if(!pre[x]) dfs2(x);
        pre[u] = min(pre[u], pre[x]);
    }
}

int main()
{
	#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    cin>>n>>m;   
    for(int i=1;i<=m;i++){
        int u,v;
        read(u), read(v);
        bfor[u].push_back(v);
        lst[v].push_back(u);
        in_degree[u]++;
    }
    if(!topo_sort()){
        puts("-1");
        return 0;
    }
    for(int i=1;i<=n;i++){
        if(!l[i]) dfs1(i);
    }
    for(int i=1;i<=n;i++){
        if(!pre[i]) dfs2(i);
    }
    for(int i=1;i<=n;i++){
        if(l[i]>=i && pre[i]>=i){
            temp++;
            ans[i] = 1;
        }
    }
    cout<<temp<<endl;
    for(int i=1;i<=n;i++){
        if(ans[i]) putchar('A');
        else putchar('E');
    }
 	return 0;
}


posted @ 2020-05-09 00:04  DinoMax  阅读(170)  评论(0)    收藏  举报