J-Fraction Comparisionjava
签到题,比较x/a 和 y/b 的大小,其中x,a,y,b的数据范围为ios
0≤x,y≤1018 1≤a,b≤109
一、能够看为带分数的形式,先比较整数部分的大小,以后再比较分数部分的大小数组
二、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; }
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("<"); } } }
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; }
二、求出的结果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; }
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; }
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; }
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; }
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; }