Educational Codeforces Round 173 (Rated for Div. 2)题解

A. Coin Transformation

思路:思考一下,会发现能不超过每消耗一个4会产生一个2,因此我们有不超过4^x次方的硬币,最多只会变为2^(x-1)的硬币

直接敲代码即可

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

int t;
int n,m,k;
int a[200005];
string s;
//快速幂公式
int fast(int a, int b) 
{
    long long result = 1;
    long long base = a;
    while (b > 0) 
	{
        if (b % 2 == 1) 
		{
            result = (result*base);
        }
        base = (base*base);
        b /= 2;
    }
    return result;
}

void solve()
{
	cin>>n;
	int flag=1;
	int ans=1;
	if(n==1)
	{
		cout<<1<<"\n";
		return ;
	}
	for(int i=1;i<=32;i++)
	{
		ans*=4;
		flag+=1;
		if(ans>n)
		break;
	}
	flag--;
	cout<<fast(2,flag)/2<<"\n";
}
signed main()
{
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

B. Digits

思路:通过分析后,会发现,数的各位数总和为为n!*d,我们可以发现,其实那个阶乘最大取到9就可以了,所以我们算出来n!*d,然后能够取模3等于0就说明3是可以的,取模9等于0就说明9也是可以的,只有d为5的时候才能包含5

我们来证明一下7的思路

我们首先可以将d全部都是1来处理,1%7=1,10%7=3,100%7=2,1000%7=6,10000%7=4,100000%7=5;

我们将前六项相加为21刚好可以整除7,所以只要n!>=6或者说n!*d整除7都是可以包含7的

1是必定被包含的

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

int t;  
int n, d;  
int vis[10]; 

void solve()  
{  
    cin >> n >> d;  
    int sum=1;
    for(int i=1;i<=min(n,9LL);i++)
    {
    	sum*=i;
	}
	sum*=d;
	cout<<1<<" ";
	if(sum%3==0)
	{
		cout<<3<<" ";
	}
	if(d==5)
	{
		cout<<5<<" ";
	}
    if(n>2)
    {
    	cout<<7<<" ";
	}
	else if((11*d)%7==0)
	{
		cout<<7<<" ";
	}
	if(sum%9==0)
	{
		cout<<9<<" ";
	}
    cout << "\n";  
}  

signed main()  
{  
    cin >> t;  
    while (t--)  
    {  
        solve(); 
    }  
    return 0;  
}

C. Sums on Segments

 思路:我们首先来判断有没有不是-1或者1的值

假如没有,那么我么直接跑个线性dpO(n)求出最大最小值,里面的元素肯定在这个范围里面

假如有,那么我们将其分为两部分,一个是特殊值左边的区间,一个是特殊值右边的区间,都是去求最大最小值,然后将其与特殊值进行加法计算,算一个新的区间的值计入那个空间中,最后输出

#include<bits/stdc++.h>  
using namespace std;  
#define int long long  
int t;  
int n, m, k;  

int a[200005];  
set<int> s;  
void solve() 
{  
    s.clear();  
    cin >> n;  
    int num=0;
    for (int i = 1; i <= n; i++) 
	{  
        cin >> a[i];  
        if(a[i]!=1&&a[i]!=-1)
        num=i;
    }  
    int maxn=0;//统计前缀最大值 
	int minn=0; //统计前缀最小值 
	int cntmin=0;
	int cntmax=0;
    if(num!=0)
    {
    	for (int i = 1; i <= num-1; i++) 
    	{
    		cntmin+=a[i];
    		cntmax+=a[i];
    		minn=min(minn,cntmin);
    		maxn=max(maxn,cntmax);
    		if(cntmin>0)
    		{
    			cntmin=0;
			}
			if(cntmax<0)
			{
				cntmax=0;
			}
		}
		cntmin=0;
	    cntmax=0;
		for (int i = num+1; i <= n; i++) 
    	{
    		cntmin+=a[i];
    		cntmax+=a[i];
    		minn=min(minn,cntmin);
    		maxn=max(maxn,cntmax);
    		if(cntmin>0)
    		{
    			cntmin=0;
			}
			if(cntmax<0)
			{
				cntmax=0;
			}
		}
	}
    else
    {
    	for (int i = 1; i <= n; i++) 
    	{
    		cntmin+=a[i];
    		cntmax+=a[i];
    		minn=min(minn,cntmin);
    		maxn=max(maxn,cntmax);
    		if(cntmin>0)
    		{
    			cntmin=0;
			}
			if(cntmax<0)
			{
				cntmax=0;
			}
		}
	}
	for(int i=minn;i<=maxn;i++)
	{
		s.insert(i);
	}
	int premax=-0; 
	int premin=0;
	int endmax=-0;
	int endmin=0;
	int ans=0;
	if(num!=0)
	{
		for(int i=num-1;i>=1;i--)
	{
		ans+=a[i];
		premax=max(premax,ans);
		premin=min(premin,ans);
	}
	ans=0;
	for(int i=num+1;i<=n;i++)
	{
		ans+=a[i];
		endmax=max(endmax,ans);
		endmin=min(endmin,ans);
	}
	for(int i=a[num]+premin+endmin;i<=a[num]+premax+endmax;i++)
	{
		s.insert(i);
	}
	}
	cout<<s.size()<<"\n";
	for(int u:s)
	{
		cout<<u<<" ";
	}
	cout<<"\n";
}  

signed main() {  
    cin >> t;  
    while (t--) {  
        solve();  
    }  
    return 0;  
}

D. Problem about GCD

我们可以将A视为a*G,B视为b*G,因此我们的gcd(a,b)=1,我们可以将左右区间缩小,同时整除G,但是我们的左区间要向上取整,右区间要向下取整,然后由于质数的稀疏性,我们完全可以只变脸左区间+20,以及右区间-20,然后找到互质的去处理即可

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

int t;
int l, r, g;
string s;
int gcd(int a,int b)
{
    if(b==0)
    {
        return a;
    }
    else
    {
        return gcd(b,a%b);
    }
}
void solve()
{
    cin >> l >> r >> g;
    int L = (l+g-1)/g;
	int R = r / g;
    int maxn = -1;
	int ansx = 1e15;
	int ansy = -1;
    for (int i = L; i <= min(R, L+20);i++)
    {
        for (int j = R; j >= max(i, R-20);j--)
        {
            if (gcd(i, j) == 1)
            {
                if (j - i > maxn)
                {
                    ansx = i;
                    ansy = j;
                    maxn = j - i;
                }
            }
        }
    }
    if (ansy == -1) 
	{
		cout << -1<<" "<<-1<<"\n";
	}
    else 
    {
    	cout << ansx * g << ' ' << ansy * g << '\n';
	}
}
signed main()
{
    cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}

 E. Matrix Transformation

思路:我们对题目上的操作进行化简,发现是以下的操作

操作1:将一整行变成0

操作2:将一整列变成1

因此我们可以用拆位的思想,将每个数都进行拆分成二进制位

然后逆向思维,先去看b数组,有0行就将0行删去,有1列就将1列删去,然后剩下的看两个数组是否相同即可,若相同就进行下一个比对,否则就是错的

#include <bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n, m;
void solve()
{
    cin >> n >> m;
    vector<vector<int>> s(n, vector<int>(m));
    vector<vector<int>> t(n, vector<int>(m));
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {
            cin >> s[i][j];
        }
    }
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {
            cin >> t[i][j];
        }
    }
    bool ok = true;
    for (int b = 0; b < 30 && ok; ++b)
    {
        vector<int> row(n), col(m), str(n), stc(m);
        vector<vector<int>> v(n, vector<int>(m));
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < m; ++j)
            {
                v[i][j] = (t[i][j] >> b) & 1;
                if (!v[i][j])
                {
                    col[j]++;
                }
                else
                {
                    row[i]++;
                }
            }
        }
        vector<int> R, C;
        for (int i = 0; i < n; ++i)
        {
            if (row[i] == 0)
            {
                R.push_back(i);
            }
        }
        for (int j = 0; j < m; ++j)
        {
            if (col[j] == 0)
            {
                C.push_back(j);
            }
        }
        while (true)
        {
            if (!R.empty())
            {
                int i = R.back();
                R.pop_back();
                str[i] = 1;
                for (int j = 0; j < m; ++j)
                {
                    if (stc[j] == 0 && v[i][j] == 0 && --col[j] == 0)
                    {
                        C.push_back(j);
                    }
                }
            }
            else if (!C.empty())
            {
                int j = C.back();
                C.pop_back();
                stc[j] = 1;
                for (int i = 0; i < n; ++i)
                {
                    if (str[i] == 0 && v[i][j] == 1 && --row[i] == 0)
                    {
                        R.push_back(i);
                    }
                }
            }
            else
            {
                break;
            }
        }
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < m; ++j)
            {
                if (str[i] == 0 && stc[j] == 0 && v[i][j] != (s[i][j] >> b & 1))
                {
                    ok = false;
                    break;
                }
            }
            if (!ok) break;
        }
    }
    cout << (ok ? "Yes" : "No") << '\n';
}

signed main()
{
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值