2019牛客暑期多校訓練營(第一場合集)

J-Fraction Comparisionjava

題目大意:

簽到題,比較x/a 和 y/b 的大小,其中x,a,y,b的數據範圍爲ios

0x,y1018 1a,b109

分析:

一、能夠看爲帶分數的形式,先比較整數部分的大小,以後再比較分數部分的大小數組

二、java大數類直接比較dom

#include<iostream>
using namespace std; long long x,a,y,b; int main() { while(cin>>x>>a>>y>>b) { if(x/a>y/b)                //比較整數部分 
            cout<<">"<<endl; else if(x/a<y/b) cout<<"<"<<endl; else { if(x%a*b>y%b*a)        //分數部分 
                cout<<">"<<endl; else if(x%a*b<y%b*a) cout<<"<"<<endl; else cout<<"="<<endl; } } return 0; }
View Code
import java.math.*; import java.util.*; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); while(input.hasNext()) { BigInteger x = input.nextBigInteger(); BigInteger a = input.nextBigInteger(); BigInteger y = input.nextBigInteger(); BigInteger b = input.nextBigInteger(); BigInteger s1 = x.multiply(b); BigInteger s2 = y.multiply(a); int h = s1.compareTo(s2); if(h == 0)System.out.println("="); else if(h == 1)System.out.println(">"); else System.out.println("<"); } } }
View Code

 

 

A-Equivalent Prefixeside

題目大意:

存在兩個長度爲n的數組,須要你求出一個q使得區間[1,q]中的各個子區間的最小值下標相同ui

分析:

一、題目須要求的是區間的最大右端點,使得1到該值的兩個數組中的任何子區間知足最小值的下標相同spa

分析能夠得出,一個數字只能影響的區間範圍是比他大的數的區間(以這個數爲最小值,向兩邊擴展,他能3d

向左擴展到第一個比該數小的數,向右也如此)code

因此兩個數組分別加入一個數,這個數字若是該數字能影響到的區間相同,則他們的最小值下標仍是相同blog

所以能夠維護兩個單調棧,判斷每次進棧後棧內元素個數是否相同,來判斷是否符合題目要求不相同則中止,

相同則更新答案

#include<iostream>
using namespace std; int n; int a[100009],b[100009]; int sta[100009],stb[100009]; int main() { while(cin>>n) { for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<=n;i++)cin>>b[i]; int ans; int topa=0,topb=0; for(int i=1;i<=n;i++) { while(topa&&sta[topa] > a[i]) topa--; sta[++topa]=a[i]; while(topb&&stb[topb] > b[i]) topb--; stb[++topb]=b[i]; if(topa==topb)ans=i; else break; } cout<<ans<<endl; } return 0; }
View Code

二、求出的結果p若是符合題意,則pos<p的區間也是符合題意的,p是單調遞增的所以能夠用二分的不斷

判斷當前的值是否知足。能夠用ST表預處理兩個數組,這樣通過logn處理後能夠O(1)時間找到區間最小值

的下標,判斷當前二分區間[1,mid]中是否知足兩個數組的最小值下標相同,若是相同,設最小值下標爲pos,

繼續遞歸判斷[1,pos-1]和[pos+1,r]是否知足要求,遞歸到最後均知足要求則表示[1,mid]區間符合。不斷二分可

求得結果

#include<iostream> #include<cstring>
using namespace std; const int MAX=100009; int a[MAX],b[MAX],n; int dpa[MAX][20],dpb[MAX][20]; void ST() { for(int i=1;i<=n;i++) dpa[i][0]=dpb[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) { int n=a[dpa[i][j-1]],m=a[dpa[i+(1<<(j-1))][j-1]]; dpa[i][j]=n<m?dpa[i][j-1]:dpa[i+(1<<(j-1))][j-1]; } for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) { int n=b[dpb[i][j-1]],m=b[dpb[i+(1<<(j-1))][j-1]]; dpb[i][j]=n<m?dpb[i][j-1]:dpb[i+(1<<(j-1))][j-1]; } } int RMQa(int l,int r) { int k=0; while(1<<(k+1)<=r-l+1) k++; int n=a[dpa[l][k]],m=a[dpa[r-(1<<k)+1][k]]; return n<m?dpa[l][k]:dpa[r-(1<<k)+1][k]; } int RMQb(int l,int r) { int k=0; while(1<<(k+1)<=r-l+1) k++; int n=b[dpb[l][k]],m=b[dpb[r-(1<<k)+1][k]]; return n<m?dpb[l][k]:dpb[r-(1<<k)+1][k]; } bool judge(int l,int r) { if(l>=r)return 1; int s1=RMQa(l,r); int s2=RMQb(l,r); if(s1!=s2) return 0; else
        return judge(l,s1-1)&&judge(s1+1,r); } int main() { while(cin>>n) { int ans; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<=n;i++)cin>>b[i]; ST(); int l=1,r=n,mid; while(l<=r) { mid=l+r>>1; if(judge(1,mid)) { l=mid+1; ans=mid; } else r=mid-1; } cout<<ans<<endl; } return 0; }
View Code

 

 

B-Integration

題目大意:

已知 給出a1...an求  結果mod (109+7).

分析:

裂項,找規律,過程以下

 

計算上述式子便可

#include<iostream> #include<cmath>
using namespace std; typedef long long ll; const int mod=1e9+7; ll pow(ll a, ll b, ll p){ ll ret = 1; while(b){ if(b & 1) ret = (ret * a) % p; a = (a * a) % p; b >>= 1; } return ret; } ll a[1009],cnt; int n; int main() { while(cin>>n) { for(int i=1;i<=n;i++) cin>>a[i]; ll ans=0; for(int i=1;i<=n;i++) { cnt=1; for(int j=1;j<=n;j++) { if(i==j)continue; cnt = cnt * (a[j]*a[j]%mod - a[i]*a[i]%mod)%mod; } ans = (pow(cnt,mod-2,mod) * pow(2*a[i],mod-2,mod) % mod + ans)%mod; } cout<<(ans%mod+mod)%mod<<endl; } return 0; }
View Code

 

 

E-ABBA

題目大意:

存在長度爲2(n+m)的包含A和B的字符串,求解可以分解爲n個AB,m個BA的字符串總數

分析:

首先能夠發現符合要求的字符串必定可以構成前n個A爲與AB匹配的,後m個A是與BA匹配的。由於知足要求的

字符串必定可以構成n個AB與m個BA,只需將前n個A用與匹配AB便可,後面的m個A用於與BA匹配。

這樣能夠用dp的作法,dp[i][j]表示i個A和j個B知足條件的字符串的種類數

存在兩種狀態即往字符串中加一個A爲dp[i+1][j]  往字符串中加一個B爲dp[i][j+1]

對於往字符串中加入一個A咱們能夠分析:當i<n時咱們能夠直接加入A,A的位置不受限制,由於A總能與後面

的B匹配獲得AB。但當i>n時,咱們便不能隨便加入A,由於當前已經存在n個A與後面的B構成AB,那麼新加入

的A須要和前面的B構成BA才能知足題目要求,所以須要判斷前面是否存在足夠的B 斷定條件爲j>i-n 若是知足

才能放入A.

得出

if(i+1<=n) 能夠直接放入下一個A else if(i+1>n)    //i+1>=n 表示前n個A與AB中B匹配,新加入需與BA中的B匹配
{ if(j>i-n)    //前面存在足夠能與A匹配成爲BA的B
 能夠放入下一個A } 

B同理  而放入A和B的遞推式也很容易能夠獲得分別是

dp[i+1][j]=(dp[i][j]+dp[i+1][j])%mod dp[i][j+1]=(dp[i][j]+dp[i][j+1])%mod

 代碼

#include<iostream> #include<cstring> #include<cstdio>
using namespace std; const int MAX=3009; const int mod=1e9+7; int n,m; int dp[MAX][MAX]; int main() { while(~scanf("%d%d",&n,&m)) { for(int i=0;i<=n+m;i++) for(int j=0;j<=n+m;j++) dp[i][j]=0; dp[0][0]=1; for(int i=0;i<=n+m;i++) for(int j=0;j<=n+m;j++) { if(j>i-n)dp[i+1][j]=(dp[i+1][j]+dp[i][j])%mod; if(i>j-m)dp[i][j+1]=(dp[i][j+1]+dp[i][j])%mod; } cout<<dp[n+m][n+m]<<endl; } return 0; }
View Code

 

 

F-Random Point in Triangle

說實話還沒學會QAQ待補坑

#include<iostream> #include<cstring> #include<cmath> #include<cstdio>
using namespace std; int main() { long long x1,y1,x2,y2,x3,y3; while(cin>>x1>>y1>>x2>>y2>>x3>>y3) { long long ans=abs(x1*y2+x2*y3+x3*y1-x1*y3-x2*y1-x3*y2); cout<<ans*11<<endl; } return 0; }
View Code

 

H-XOR

題目大意:

給你一個集合S,求集合中全部知足異或和爲0的子集大小之和

分析:

求解爲子集的大小和,能夠轉化爲求每一個元素在集合中出現的次數,算出每一個元素的貢獻後求和即爲答案

題目要求子集要知足異或和的大小和爲0,異或的性質c ^ c = 0,所以及判斷一個元素可否被其餘集合的元素通

過異或的方式表示出來,到這裏能夠發現用線性基解決此問題。

首先求出n個數字的線性基,設線性基大小爲r。

一、在線性基外元素:不在線性基中的n-r個數的任意組合能被線性基所表示(每一個數都能被線性基中的元素組合所

表示,每一個數的組合異或值也能被元素組合表示),即異或得出結果爲0,枚舉n-r個數的每一個數,都有2(n-r-1)種組

合方式(能夠當作該元素必定被選中,剩下n-r-1個元素都有選和不選兩種狀況),所以線性基外元素貢獻爲   

(n-r) * 2(n-r-1)

二、在線性基內元素:枚舉線性基內r個元素每一個元素,若剩餘n-1個元素可以表示該元素(該元素不能放入剩餘n-1

個元素構成的線性基),該元素爲線性基外元素,貢獻與第一種狀況同樣,爲2(n-r-1) (若該元素可以放入剩餘n-1個

元素線性基)則沒法用n-1個元素的線性基表示該數,貢獻爲0

這裏求n-1個元素的線性基能夠先將第一次處理的n-r個元素的線性基求出,每次往該線性基插入剩餘的r-1個元素便可

代碼:

#include<iostream> #include<cstring> #include<cstdio>
using namespace std; const int MAX=1e5+9; const int mod=1e9+7; typedef long long ll; int n,cnt; ll a[MAX]; //輸入的集合 長度爲n 
ll tempa[MAX];  //在線性基中的元素 
ll ans; struct LinerBase { int tot; ll b[65]; void init(){ tot=0; memset(b,0,sizeof(b)); } bool insert(ll x){ for(int i=60;i>=0;i--){ if(x&(1ll<<i)){ if(!b[i]){ b[i]=x; tot++; return true; } else x^=b[i]; } } return false; } bool check(ll x){ for(int i=60;i>=0;i--){ if(x&(1ll<<i))x^=b[i]; } return !x; } }Ba,Bb,Bc; //Ba:集合的線性基 長度爲r //Bb:不在線性基中的n-r個元素的線性基 //Bc:除去線性基中一個數剩餘n-1個數的線性基
ll qpow(ll a,ll n) { ll re=1; while(n) { if(n&1) re=(re*a)%mod; n>>=1; a=(a*a)%mod; } return re%mod; } int main() { while(~scanf("%d",&n)) { Ba.init(),Bb.init(); memset(tempa,0,sizeof(tempa)); ans=0;cnt=0; for(int i=0;i<n;i++) scanf("%lld",&a[i]); for(int i=0;i<n;i++) { if(!Ba.check(a[i])) { Ba.insert(a[i]); tempa[cnt++]=a[i]; } else Bb.insert(a[i]); } if(Ba.tot==n) { printf("0\n"); continue; } ans += (n-Ba.tot) * qpow(2,n-Ba.tot-1) % mod; for(int i=0;i<cnt;i++) { Bc.init(); for(int j=0;j<cnt;j++) if(i!=j)Bc.insert(tempa[j]); for(int j=0;j<=60;j++) if(Bb.b[j]) Bc.insert(Bb.b[j]); if(Bc.check(tempa[i])) ans = (ans + qpow(2,n-Ba.tot-1)) % mod; } printf("%lld\n",ans); } return 0; } 
View Code
相關文章
相關標籤/搜索