2018黑龍江省賽(upc7215-upc7224)(solve8/10)

題目沒連接,除了Upc,沒找到其他開發OJ有此題,如果有連接,請評論區留言下,謝謝~

A題:

題意:給你一個字符串問你只有一種字母的子串有多少。

思想:直接暴力連續的字符串數  結果等於每個連續字符的(長度*長度+1)/2

B 題:

不會~

C題

題意:給你x1,x2,y1,y2,(x1<x2,y1<y2)問你從x1到y1的同時x2到y2不想交的路徑有多少

思想:Lindström–Gessel–Viennot定理  解決DAG圖中n條不交叉路徑問題,比賽的時候知道是這個但是腦子瓦特了,煩。

定理可以看下這個博客:https://blog.csdn.net/ftx456789/article/details/81132126

逆元預處理組合數

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod =1e9+7;
const int maxn=1e6+5;
ll fac[maxn],inv[maxn];
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
void init()
{
    fac[0]=1;
    for (int i=1;i<maxn;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[maxn-1]=qpow(fac[maxn-1],mod-2);
    for (int i=maxn-2;i>=0;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll n,ll m){
    if (n<m) return 0;
    return ((fac[n]*inv[m]%mod)%mod*inv[n-m]%mod)%mod;
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll a,b,c,d;
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        ll temp=(C(a+c,a)*C(b+d,b))%mod;
        ll Temp=(C(a+d,a)*C(b+c,b))%mod;
        temp=(temp-Temp+mod)%mod;
        printf("%lld\n",temp);
    }
    return 0;
}

D題

題意:給你n個數,然後m次詢問,每次問你區間的數,是否是連續的數。

思想:莫隊維護區間,RMQ求區間最值。莫隊維護區間不同數的個數,RMQ求一下區間最大和最小值,看下當前區間出現的數是否等於Max-Min+1個即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int b[maxn];
int kuai[maxn];
int vis[maxn];
int Maxx[maxn][25];
int Minn[maxn][25]; 
int cnt[maxn];
struct node{
    int l;
    int r;
    int id;
}no[maxn];
int ans,n,m;
int cmp(node a,node b)
{
    if(kuai[a.l]==kuai[b.l])
        return a.r<b.r;
    return a.l<b.l;
}
void init()
{
    for(int j=1;j<=20;j++)
    {
        for(int i=1;i+(1<<j)<=n+1;i++)
        {
            Maxx[i][j]=max(Maxx[i][j-1],Maxx[i+(1<<(j-1))][j-1]);
            Minn[i][j]=min(Minn[i][j-1],Minn[i+(1<<(j-1))][j-1]);
        }
    }
}
int RMQmax(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1) 
        k++;
    return max(Maxx[l][k],Maxx[r-(1<<k)+1][k]);
}
int RMQmin(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1) 
        k++;
    return min(Minn[l][k],Minn[r-(1<<k)+1][k]);
}
void add(int l)
{
    cnt[a[l]]++;
    if(cnt[a[l]]==1)
        ans++;
}
void del(int l)
{
    cnt[a[l]]--;
    if(cnt[a[l]]==0)
        ans--;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(cnt,0,sizeof(cnt));
        scanf("%d%d",&n,&m);
        int black=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);  
            b[i]=a[i];
            kuai[i]=i/black+1;
            Maxx[i][0]=a[i];
            Minn[i][0]=a[i];
        }
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&no[i].l,&no[i].r);
            no[i].id=i;
        }
        sort(b+1,b+1+n);
        int k=unique(b+1,b+1+n)-b-1;
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(b+1,b+1+k,a[i])-b;
        int l=1;
        int r=0;
        ans=0;
        sort(no+1,no+1+m,cmp);
        for(int i=1;i<=m;i++)
        {
            while(l<no[i].l)
                del(l++);
            while(l>no[i].l)
                add(--l);
            while(r<no[i].r) 
                add(++r);
            while(r>no[i].r)
                del(r--);
            int Max=RMQmax(no[i].l,no[i].r);
            int Min=RMQmin(no[i].l,no[i].r);
            if(Max-Min==ans-1)
                vis[no[i].id]=1;
            else
                vis[no[i].id]=0;
        }
        for(int i=1;i<=m;i++)
        {
            if(vis[i]==1)
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
} 

E題

題意:給你x,y。問你x個東西均分y個人,讓其中獲得最多的人和最小的人的差值最小。

思路:x%y==0 則是0否則是1

F題

題意:給你2個串,問你A的子串和B的子串(長度相等)不同位置不超過k,這個子串的長度最長爲多少。
思想:枚舉A的子串的起點去匹配B串,枚舉B串子串的起點去匹配A串。匹配的時候尺取法去匹配。n^2*T=8e7

#include<bits/stdc++.h>
using namespace std;
int k,ans;
char a[4005];
char b[4005];
void check(char c[],char d[])
{
	int sum=0;//標記已經有多少個不同 
	int len=min(strlen(c),strlen(d));
	
	for(int l=0,r=-1;l<len;l++)
	{
		while(r+1<len && sum+(c[r+1]!=d[r+1])<=k)
		{
			r++;
			sum+=c[r]!=d[r];
		}	
		ans=max(ans,r-l+1);
		sum-=(c[l]!=d[l]);	
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&k);
		scanf("%s%s",a,b);
		ans=0;	
		int Len=strlen(a);
		for(int i=0;i<Len;i++)	
			check(a+i,b);
		Len=strlen(b);
		for(int i=0;i<Len;i++) 
			check(b+i,a);
		printf("%d\n",ans);
	} 
	return 0;
} 

G題

題意:給你n個花的高度,每次修改n-1盆花,問你是否出現所有花一樣高的局面,沒有輸出-1,有的話輸出最少的時間。

思想:假設a[0]減去X下,a[1]減去Y下,a[2]減去Z下~~~~~這樣先將全部拍個序列,考慮如果所有的花減去的長度等於sigma(max-a[i])(i>=1 && i<=n)的話,這樣所有的花都到了一個統一的高度,考慮最矮的那個花是否可以sum-(Max-a[0])>0,如果不行的話那麼就輸出-1,如果行的話,那麼輸出就等於sum。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		sort(a,a+n);
		int ans=0;
		for(int i=1;i<n;i++)
			ans+=a[n-1]-a[i];
		if(ans>=a[0])
			printf("-1\n");
		else
			printf("%d\n",ans+a[n-1]-a[0]);
	}
	return 0;
} 

H題

題意:就是給你n個立方體的邊長和密度,然後給你一個底面積爲S,高爲H,現在有V體積水的一個容器,然後問你最後水的高度。

思想:我深切感覺題意有問題,題意沒有說明重的一定都會沒進去,可能出題人的沒表達清楚?或者我菜?

密度>=1 全放進去,小於1的就按照比例放就好了,別忘了加上原來的水就行了。

I題

據說是AC自動機+DP

J題

題意:給你一個序列,問你最少交換多少次可以讓序列變回一個有序的序列。

思想:如果是交換相鄰的話,就變成了求逆序對,然而是隨意交換的話,就相等於判斷有多少個環即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int b[maxn];
int vis[maxn]; 
int Vis[maxn]; 
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		memset(vis,0,sizeof(vis));
		memset(Vis,0,sizeof(Vis));
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			b[i]=a[i];
		}
		sort(b,b+n);
		for(int i=0;i<n;i++)
			Vis[b[i]]=i;
		int ans=n;
		for(int i=0;i<n;i++) 
		{
			if(vis[i]==0)
			{
				int temp=i;
				while(vis[temp]==0) //跑一個環
				{
					vis[temp]=1;
					temp=Vis[a[temp]]; 
				} 
				ans--;//一個環少交換一次 
			}
		}
		printf("%d\n",ans);
	} 
	return 0;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章