ACM-ICPC 2018 徐州赛区网络预赛(部分题解)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/passer__/article/details/82562411

题目链接:https://www.jisuanke.com/contest/1557?view=challenges

A题

题意:给你2^k个面具,然后n个人,要求挨着的2个人二进制之后不能互补。问你有多少不同的方案数

思想:对于这2^k个数最多就两个数是互补的,所以考虑下第一个数有2^k种选择,第二个2^k-1种,假如倒数第二个跟第一个不一样,那么最后一个由2^k-2种选择,假如一样的话,那么就可以将序列缩短到n-2,继续递归下去计算。

Ps:对于第一个题,可以推那个容斥的公式,或者看下这个DP写的非常好:http://www.cnblogs.com/565261641-fzh/p/9616556.html

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod =1e9+7;
const int maxn=1e6+5;
ll a[maxn];
void init()
{
    a[0]=1;
    for(int i=1;i<maxn;i++)
		a[i]=(a[i-1]*2ll)%mod;
}
ll Pow(ll n, ll m)
{
    ll ans=1;
    while(m)
    {
        if(m&1)
            ans=(ans*n)%mod;
    	n=(n*n)%mod;
        m=m>>1;
    }
    return ans%mod;
}
ll check(ll n,ll k)
{
	if(n==1)//只有一个人
        return a[k]%mod;
    else if(n==2)//只有两个人
        return (a[k]*(a[k]-1))%mod;
    ll ans;
    ans=((a[k]*Pow((a[k]-1),n-2)%mod)*(max(a[k]-2ll,0ll)))%mod;
    ans=(ans+check(n-2,k)%mod)%mod;
    return ans;
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
     	ll  n,k;
        scanf("%lld%lld",&n,&k);
        ll T=check(n,k);
        printf("%lld\n",T);
    }
    return 0;
}

F题

题意:给你n帧画面,问你最长的连续点的长度是多少,就是对于i中有(1,1)下一秒还有 那么长度就2,也就说答案要不是0要不就大于2;

思想 map搞一下,模拟那个过程即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
struct point{
    int x, y;
}a[100005];
int ans[100005];
map<pair<int, int> , int>mp, mpp;

int main()
{
    int T, n, c, maxx;
    scanf("%d", &T);
    while(T--){
        mp.clear();
        scanf("%d", &n);
        maxx = 0;
        for(int i = 0; i < n; i++){
            scanf("%d", &c);
            for(int j = 0; j < c; j++){
                scanf("%d%d", &a[j].x, &a[j].y);
                pair<int, int> p(a[j].x, a[j].y);
                if(!mpp[p]){
                    mpp[p] = 1;
                    mp[p]++;
                }
                int temp = mp[p];
                ans[j] = temp;
                if(temp > maxx)
                    maxx = temp;
            }
            mpp.clear();
            mp.clear();
            for(int j = 0; j < c; j++){
                pair<int, int> p(a[j].x, a[j].y);
                mp[p] = ans[j];
            }
        }
        if(maxx > 1)
            printf("%d\n", maxx);
        else
            printf("0\n");
    }
    return 0;
}

G题

题意:就是给你n次冲浪形成的一个矩阵,每次都会留下一个痕迹,但是也有可能会毁掉原来留下的痕迹,问你痕迹的长度是多少。

思想:两个树状数组,维护X和Y的最大值,从后往前,因为前边有可能被后边的干掉。发现对于某次海浪,改变的值等于比当前X大的的所有X里面的Y最大值和当前Y的差值,X同理。

扫描二维码关注公众号,回复: 3138957 查看本文章
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=50005;
ll x[maxn];
ll y[maxn];
ll Qx[maxn*200];
ll Qy[maxn*200];
void add(int x,ll valu)
{
	for(ll i=x;i>0;i-=(i&(-i)))
		Qy[i]=max(Qy[i],valu);
}
void Add(int x,ll valu)
{
	for(ll i=x;i>0;i-=(i&(-i)))
		Qx[i]=max(Qx[i],valu);	
}
ll query(ll x)
{
	ll ans=0;
	for(ll i=x;i<maxn*200;i+=(i&(-i)))
		ans=max(ans,Qy[i]);	
	return ans;
}
ll Query(ll x)
{
	ll ans=0;
	for(ll i=x;i<maxn*200;i+=(i&(-i)))
		ans=max(ans,Qx[i]);
	return ans;
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%lld%lld",&x[i],&y[i]);
	ll sum=0;
	for(int i=n-1;i>=0;i--)
	{
		ll temp=query(x[i]);//比X[i]大的最大的y 
		sum=sum+y[i]-temp;
		temp=Query(y[i]);//比y[i]大的最大的x 
		sum=sum+x[i]-temp;
		
		add(x[i],y[i]);
		Add(y[i],x[i]);
	//	printf("%lld\n",sum);
	}
	printf("%lld\n",sum);
	return 0;
}
 

H题

题意:有n个数,q次询问,每次不是问区间那个式子的值,要不就是改变某点的值。

思想:树状数组,一个建立a[i] 一个建立i*a[i] ,维护即可,为什么这样 自己画画,就OK了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Maxn=1e5+5;
ll a[Maxn];
ll b[Maxn];
ll c[Maxn];
int n,q;
void add(int x,ll num)
{
	while(x<=n)
	{
		b[x]+=num;
		x+=(x&(-x));
	}
}
void Add(int x,ll num)
{
	while(x<=n)
	{
		c[x]+=num;
		x+=(x&(-x));
	}
}
ll query(int x)
{
	ll ans=0;
	while(x)
	{
		ans+=b[x];
		x-=(x&(-x)); 
	}
	return ans;
}
ll Query(int x)
{
	ll ans=0;
	while(x)
	{
		ans+=c[x];
		x-=(x&(-x));
	}
	return ans;
}
int main()
{
	scanf("%d%d",&n,&q);
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		add(i,a[i]);
		Add(i,i*a[i]);
	}
	while(q--)
	{
		int op,x;
		ll y;
		scanf("%d%d%lld",&op,&x,&y);
		if(op==1)
		{
			ll temp=(y+1)*(query(y)-query(x-1));
			ll Temp=temp-(Query(y)-Query(x-1));
			printf("%lld\n",Temp);
		}
		else
		{
			add(x,-a[x]);
			Add(x,-x*a[x]);
			a[x]=y;
			add(x,a[x]);
			Add(x,x*a[x]);
		} 
	}
	return 0;
} 

I题

题意:给你个单词和字符串,对于字符串的每个单词可以通过已给的方式得到一个2位数,然后拼接len*2个数字,去掉前导0多长。

思想:模拟

#include<bits/stdc++.h>
using namespace std;
char str[1000005];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{	
		int n,ans=0;
		char c;
		scanf("%d %c",&n,&c);
		scanf("%s",str);
		int len=strlen(str);
		vector<int>V;
		for(int i=0;i<len;i++)
		{
			int temp=abs((int)(c)-str[i]);
			int T=temp%10;
			temp=temp/10;
			temp=temp%10;
			V.push_back(temp);
			V.push_back(T);
		}
		for(int i=0;i<V.size();i++)
		{
			if(V[i]==0)
				ans++;
			else
				break;	
		}
		printf("%d\n",max(1,(int)V.size()-ans));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/passer__/article/details/82562411