[EC Final 2020] ICPC2020 东亚赛区决赛重现赛题解

比赛链接:EC Final 2020

和 @cyx20110930 组的队,用他的号交的题。顺便帮助他橙名,好耶!(rk 25,我俩各写 2 道)

Problem B:

这道是 @cyx20110930 写的,顺便安利(copy)一下他的题解

题目意思

有一个n\times m的棋盘,操作n\times m次,每次删掉一个方格,问还剩几个长方形。

思路

正难则反,既然数有多少个比较困难,就直接每次查找少了几个长方形,十分简单。

代码

//暴力
//TEAM_NAME:CYX&LSY AK ICPC
//Problem B
//By CYX
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,down[505][505],up[505][505],grid[505][505];
int main()
{
    cin>>n>>m;
    //预处理
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++){
            up[i][j]=0;
            down[i][j]=n+1;
        }
    }
    int ans=n*(n+1)/2*m*(m+1)/2,q=n*m;
    while(q--){
        int x,y;
        cin>>x>>y;
        int u=0,d=n+1;
        for(int j=y;j>=1;j--){//从1至y找u,d,看对每个格子能影响多大区域
            if(grid[x][j]) break;
            u=max(u,up[x][j]+1);
            d=min(d,down[x][j]-1);
            int a=u,b=d;
            for(int k=y;k<=m;k++){//从y至n找u,d,看对每个格子能影响多大区域
                if(grid[x][k]) break;
                a=max(a,up[x][k]+1);
                b=min(b,down[x][k]-1);
                ans-=abs(x-a+1)*abs(b-x+1);
            }
        }
        cout<<ans<<endl;
        //更新
        grid[x][y]=1;
        for(int j=x;j<=n;j++)up[j][y]=max(up[j][y],x);
        for(int j=x;j>=1;j--)down[j][y]=min(down[j][y],x);
    }
	return 0;
}

Problem F:

这题是我写的awa。

题目意思

有一个无限大的象棋棋盘,两个玩家分别有n,m个车,放置在(x,y)上。

两个车可以被相互攻击要满足这三个条件:

        ①属于不同的玩家

        ②有相同的x或者y

        ③中间没有其他棋子

输出有哪些车可以被攻击到。

思路

我们直接用一个 map 来保存相同行和相同列的棋子,这里我们可以把车按照不同的玩家分为i,i+n。然后我们遍历同一行/列的棋子,看看是否属于不同的玩家。

代码

//模拟
//TEAM_NAME:CYX&LSY AK ICPC
//Problem F
//By LSY
#include <bits/stdc++.h>
using namespace std;
struct rook{
	int pos;
	int id;
};
map<int,vector<rook>> row;
map<int,vector<rook>> col;
bool ans[400005];
bool cmp(rook x,rook y){
	return x.pos<y.pos;
}
int main(){
	int n1,n2;
    cin>>n1>>n2;
    for(int i=1;i<=n1;i++){
        int a,b;
		cin>>a>>b;
        row[a].push_back({b,i});
        col[b].push_back({a,i});
    }
    for(int i=1;i<=n2;i++){
        int a,b;
		cin>>a>>b;
        row[a].push_back({b,i+n1});
        col[b].push_back({a,i+n1});
    }
    for(auto p:row){
        auto c=p.second;
        sort(c.begin(),c.end(),cmp);
        for(int i=1;i<c.size();i++){
            if((c[i].id<=n1 && c[i-1].id>n1) || (c[i-1].id<=n1 && c[i].id>n1)){
                ans[c[i].id]=1;
				ans[c[i-1].id]=1;
			}
        }
    }
    for(auto q:col){
        auto r=q.second;
        sort(r.begin(),r.end(),cmp);
        for(int i=1;i<r.size();i++){
            if((r[i].id<=n1 && r[i-1].id>n1) || (r[i-1].id<=n1 && r[i].id>n1)){
                ans[r[i].id]=1;
				ans[r[i-1].id]=1;
            }
        }
    }
    for(int i=1;i<=n1;i++)
		cout<<ans[i];
    cout<<endl;
    for(int i=n1+1;i<=n1+n2;i++)
		cout<<ans[i];
    return 0;
}

Problem K:

继续copy @cyx20110930 的题解

题目意思

每人 2 张牌,公共牌区 5 张牌,现在给你你的牌,与公共牌区的 3 张牌,问你是否保证胜利。

思路

只有同花顺可能 Allin。(保证胜利)

证明:

题目给定的牌为 h1,h2,c1,c2,c3 设对方的两张为 g1,g2 剩下两张未给出的公共牌为 c4,c5。

若给定的五张牌次于四张一样(炸弹)的牌型,则存在 g1=g2=c4=c5 使得对方构成炸弹的牌型,故不可 Allin。

若给定的五张牌构成炸弹的牌型,此时由于四种花色都有,则一定有一张公共牌的花色不同于 h1 与 h2,不妨设这张牌为 c1,那么存在一种方案使得 c1,c4,c5,g1,g2 构成同花顺,故不可 Allin。

当给定的五张牌为同花顺,此时可枚举对方牌型,看是否有赢的可能。对方赢的牌型必须满足以下条件:

  • 是大于给定五张牌的同花顺

  • 没有 h1,h2

  • 至少包含 c1,c2,c3 其中一张

综上,证毕。

代码

当时他口胡出了上面的思路,丢给我写的。(CYX op)

//模拟
//TEAM_NAME:CYX&LSY AK ICPC
//Problem K
//By LSY
#include <bits/stdc++.h>
using namespace std;
string h1,h2,c1,c2,c3;
vector<int> v;
int transfer(string x){
    if(x[0]>='0' && x[0]<='9')
        return x[0]-'0';
    if(x[0]=='T')
        return 10;
    if(x[0]=='J')
        return 11;
    if(x[0]=='Q')
        return 12;
    if(x[0]=='K')
        return 13;
    if(x[0]=='A')
        return 14;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        v.clear();
        string h1,h2,c1,c2,c3;
        cin>>h1>>h2>>c1>>c2>>c3;
        int flag=0,p=0;
        if(h1[1]==h2[1] && h2[1]==c1[1] && c2[1] == c1[1] && c3[1] == c2[1]){
            v.push_back(transfer(h1));
            v.push_back(transfer(h2));
            v.push_back(transfer(c1));
            v.push_back(transfer(c2));
            v.push_back(transfer(c3));
            sort(v.begin(),v.end());
            for(int i=1;i<v.size();i++){
                if(v[i-1]+1==v[i])
					continue;
                else{
                	p=1;
					break;
				}
            }
            if(!p){
                if(max(transfer(h1),transfer(h2))>=10)
					flag=1;
                if(max(transfer(h1),transfer(h2))>=max(max(transfer(c1),transfer(c2)),transfer(c3)))
					flag=1;
            }
        }
        if(flag){
            cout<<"Allin"<<endl;
            continue;
        } 
        v.clear();
        if(transfer(h1)==14 && transfer(h2)==5){
            if(h1[1]==h2[1] && h2[1]==c1[1] && c2[1]==c1[1] && c3[1]==c2[1]){
                v.push_back(transfer(c1));
                v.push_back(transfer(c2));
                v.push_back(transfer(c3));
                sort(v.begin(),v.end());
                if(v[0]==2 && v[1]==3 && v[2]==4){
                    cout<<"Allin"<<endl;
                    continue;
				}
            }
        }
        if(transfer(h2)==14 && transfer(h1)==5){
            if(h1[1]==h2[1] && h2[1]==c1[1] && c2[1]==c1[1] && c3[1]==c2[1]){
                v.push_back(transfer(c1));
                v.push_back(transfer(c2));
                v.push_back(transfer(c3));
                sort(v.begin(),v.end());
                if(v[0]==2 && v[1]==3 && v[2]==4){
					cout<<"Allin"<<endl;
					continue;
				}
            }
        }
        cout<<"check"<<endl;
    }
    return 0;
}

Problem L:

依旧是搬运 @cyx20110930 的题解

题目意思

有一个数组a_1,a_2,a_3......,a_n​,求出乘积最小的 t 数组t_1,t_2,t_3,......t_n使得对于每个 i(1\leq i\leq n),a_i\times t_i\times a_{i+1}\times t_{i+1}是完全平方数。

思路

明显对于每个a_i\times t_i其因数的出现次数只有两种情况:都是奇数或都是偶数。

对这两种情况分别计算,取最小值即可。

代码

//签到
//TEAM_NAME:CYX&LSY AK ICPC
//Problem B
//By CYX
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
bool isprime[1000005];
int pri[1000005],s[1000005],vis[1000005],num[1000005],prime[1000005],cnt,tot;
void init(){
	s[1]=1;
	for(int i=2;i<=1000005;i++){
		if(!isprime[i])prime[++cnt]=i,s[i]=i;
		for(int j=1;j<=cnt;j++){
			if(i*prime[j]>1000005)break;
			isprime[i*prime[j]]=1;
			s[i*prime[j]]=prime[j];
			if(!(i%prime[j]))break;
		}
	}
}
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=ans*a%1000000007;
		a=a*a%1000000007;
		b>>=1;
	}
	return ans;
}
int main(){
	init();
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;cin>>x;
		tot=0;
		while(x>1){
			if(!vis[s[x]])pri[++tot]=s[x];
			vis[s[x]]++;
			x/=s[x];
		}
		for(int j=1;j<=tot;j++){
			if(vis[pri[j]]%2==1)num[pri[j]]++;
			//num是指数为奇数的质因子的出现次数
			vis[pri[j]]=0;
		}
	}
	int ans=1;
	for(int i=1;i<=cnt;i++){
		if(!num[prime[i]])continue;
		ans*=qpow(prime[i],min(num[prime[i]],n-num[prime[i]]));
		ans%=1000000007;
	}
	cout<<ans;
	return 0;
}

友情提醒:不要Ctrl C+Ctrl V

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值