我是个菜鸡,天天被大佬吊打,这次考试的自己也只做出了第一题,惨遭挂科
正方形边长为1,E是对角线BD上一点,F是边AB上一点,已知|DE|=a/b|DB|,|BF|=c/d|AB|,求△CEF的面积。
思路:推公式,注意为负数的情况
#include
#include
using namespace std;
int main(){
int t;
scanf("%d",&t);
while(t--){
int a,b,c,d;
scanf("%d %d %d %d",&a,&b,&c,&d);
int m=b*d-a*c-a*d;
int n=2*b*d;
if(m==0){
printf("0\n");
continue;
}
if(m<0) m=abs(m);
int k=__gcd(m,n);
m/=k,n/=k;
printf("%d/%d\n",m,n);
}
return 0;
}
有n个球,标号为1∼n,第i个球有的颜色为ci。你需要选择3个不同颜色的球,问有多少种不同的选择方案?
思路:先hash统计各个颜色气球数量(可以map,unordered_map,unordered_map应该不会超时,map不知道)
然后因为直接数三个不同色的很困难,这里就得用到间接法,但是谢大认为这是小学三年级知识,其实我们大部分人都没想到.
就是用从n个球中选出3个球的方案数(即组合数C n 选3) 减去 三球同色 减去 两球同色,即为三球不同色的方案数,复杂度是O(n)的,可以接受
坑点:64位如果是scanf输入记得用__int64,不然会wa,用cin的可以不用管
#include
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
#define Debug(x) cout<<#x<<':'<<x<<endl
typedef long long ll;
#define INF 0x7fffffff//10^9级别,不到2^32
#define mo 20011
#define maxn 10000
ll re[mo+11];
inline ll hash1(ll n){
ll x=n%mo;
if(re[x]==INF) {re[x]=n;return x;}
else{
ll i=0;
while(re[(x+i)%mo]!=INF){
if(re[(x+i)%mo]!=n) i++;
else return (x+i)%mo;
}
re[(x+i)%mo]=n;
return (x+i)%mo;
}
}
void init(){//哈希表初始化
for(ll i=0;i<mo;i++) re[i]=INF;
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
ll t;
cin>>t;
while(t--){
init();
ll co[mo+11]={0};
ll ar[mo+11]={0};
ll n;
cin>>n;
for(ll i=1;i<=n;i++){
ll t;cin>>t;
co[hash1(t)]++;
}
ll step=0;
for(ll i=0;i<mo;i++){
if(co[i]!=0){
ar[++step]=co[i];
}
}
ll ans=n*(n-1)*(n-2)/6;
for(ll i=1;i<=step;i++){
if(ar[i]>=3) ans=ans-ar[i]*(ar[i]-1)*(ar[i]-2)/6;
if(ar[i]>=2) ans=ans-ar[i]*(ar[i]-1)/2*(n-ar[i]);
}
cout<<ans<<endl;
}
return 0;
}
序列X由线性产生式 xn=axn−1+bxn−2,x0=x1=1 产生,
序列Y由线性产生式 yn=cyn−1+dyn−2,y0=y1=1 产生,
集合Z={x+y∣x∈X,y∈Y}。
现有区间[L,R],求最长的子区间[l,r],满足L≤l≤r≤R,∀z∈[l,r],z∈Z。
思路:题目看似数据量很大,到10^9,我也是一开始被吓到了
其实不然,仔细分析
因为斐波那契数列增长很快,约为2的x次方,指数级别
所以x中最多到差不多50项,就会超出1e9次方,即x中最多50个元素
同理,y中最多也只有50个,那么z中最多就只有50*50个
可以枚举产生Z 复杂度可以接受
最后再在L~R区间内遍历一遍,找出最长子区间即可
坑点:最好用64位,不然容易爆int,很多人re了我不知道什么原因
#include
#pragma comment(linker, "/STACK:102400000,102400000")//解决递归函数多次调用栈溢出问题
using namespace std;
#define Debug(x) cout<<#x<<':'<<x<<endl
typedef long long ll;
#define INF 0x7fffffff//10^9级别,不到2^32
const ll maxn=1e9;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
ll t;
cin>>t;
while(t--){
ll a,b,c,d,l,r;
ll x[55]={1,1,1},y[55]={1,1,1};
ll re[2555],step=1;
cin>>a>>b>>c>>d>>l>>r;
ll l1=2,l2=2;
for(ll i=3;i<55;i++){
x[i]=a*x[i-1]+b*x[i-2];
l1++;
if(x[i]<=0 || x[i]>=1e9) break;
}
for(ll i=3;i<55;i++){
y[i]=c*y[i-1]+d*y[i-2];
l2++;
if(y[i]<=0 || y[i]>=1e9) break;
}
for(ll i=1;i<l1;i++){
for(ll j=1;j<l2;j++){
if(l<=x[i]+y[j] && x[i]+y[j]<=r){
re[step++]=x[i]+y[j];
//Debug(re[step-1]);
}
}
}
sort(re+1,re+step);
step=unique(re+1,re+step)-(re+1);
if(step==0) cout<<0<<endl;
else{
ll length=1,maxl=1;
for(ll i=2;i<=step;i++){
//Debug(re[i]);
if(re[i]==re[i-1]+1){
length++;
if(length>maxl) maxl=length;
}
else length=1;
}
cout<<maxl<<endl;
}
}
return 0;
}
积木块都是相同的立方体,一共有n列积木堆,这n列积木排成一排,每堆上是ai个积木堆叠起来,并且保证从左到右,每列的积木数是非递减的。
现在你还有k个积木块,请把这k个积木块放到积木上(可以只用部分积木块,但不能堆新的列)。你想的到一个连续的积木列,并使得这些积木列具有相同的高度。
请问你能得到这样的积木列的最大宽度?
思路:
最长区间问题,容易想到尺取,要用尺取,序列就得满足单调性,这题随着区间长度递增,k值是递增的,满足单调性.
具体来说就是用两个指针,一个右指针指向区间右边端点,一个左指针指向区间左边端点,用sum值记录这个区间内满足连续积木列所需的木块数,当sum<=k时,右指针右移,区间长度+1,当sum>k时,左指针右移,区间长度-1.记录下满足条件的最大长度
小提示:“巨大的输入量,请使用stdio.h头文件,并使用C风格的输入”,这句话在xtu oj经常有,但其实关了同步,用cin也不是很慢.像这道题就是.
#include
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
#define Debug(x) cout<<#x<<':'<<x<<endl
typedef __int64 ll;
#define INF 0x7fffffff//10^9级别,不到2^32
const ll maxn=10000+11;
ll ar[maxn];
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
ll t;
cin>>t;
while(t--){
ll n,k;
cin>>n>>k;
for(ll i=1;i<=n;i++) cin>>ar[i];
ll l=1,r=1,length,maxl,k1=0;
for(ll r=1;r<=n;r++){
if(r==1){
length=1;
maxl=1;
}
else{
if(ar[r]!=ar[r-1]) k1=k1+(r-l)*(ar[r]-ar[r-1]);
length++;
while(k1>k){
k1=k1-(ar[r]-ar[l]);
length--;
l++;
}
if(length>maxl) maxl=length;
}
}
cout<<maxl<<endl;
}
return 0;
}
另一个思路:最长区间长度,由关键词最长,也容易想到二分,就是二分枚举最大宽度,对于每个宽度check下是否符合要求
n个元素,依次插入一颗初始为空的二叉查找树。对于第i个元素,其所在二叉查找书的左右子树深度差的绝对值为di,求max{di}。
板子题,直接套数据结构书上的模板就行了,思路没啥好讲的
#include
#include
using namespace std;
typedef struct Node * BST;
struct Node{
int num;
BST left;
BST right;
};
int GetHeight(BST a);
BST Insert(BST a,int b);
BST Free1(BST a);
int max_num;
int main(){
int t;
scanf("%d",&t);
while(t--){
max_num=0;
int n;
scanf("%d",&n);
BST root;
root=NULL;
for(int i=0;i<n;i++){
int b;
scanf("%d",&b);
root=Insert(root,b);
}
GetHeight(root);
printf("%d\n",max_num);
Free1(root);//free大大减少OJ上的空间
}
return 0;
}
int GetHeight(BST a){
if(!a) return 0;
int d,max_2,hl,hr;
hl=GetHeight(a->left);
hr=GetHeight(a->right);
max_2=hl>hr?hl:hr;
d=abs(hr-hl);
if(d>max_num) max_num=d;
return (max_2+1);
}
BST Insert(BST a,int b){//递归插入相对耗时较长
if(!a){//为空树时也可以插入
a=(BST)malloc(sizeof(struct Node));
a->num=b;
a->left=a->right=NULL;
}
else{
if(b>a->num) a->right=Insert(a->right,b);
else if(b<a->num) a->left=Insert(a->left,b);
//b==a->num情况不考虑
}
return a;
}
BST Free1(BST a){
if(a){//若未考虑非空情况,会导致出错!
if(a->left==NULL && a->right==NULL){
free(a);
a=NULL;
return NULL;
}
a->left=Free1(a->left);
a->right=Free1(a->right);
free(a);
a=NULL;
return NULL;
}
else return NULL;
}
为了压缩一个只含小写英文字母的字符串,我们使用下面的方式表示它
任一字母c是表达式
任一字母c后接一个整数n也是一个表达式,表示把字母c重复n次,n是一个没有前导零的10进制整数,且 n≥2。
如果s1,s2是表达式,那么s1s2也是表达式。
S是一个表达式,那么(S)n也是表达式,表示将S这个表达式表示的字符串重复n次,n是一个没有前导零的10进制整数,且 n≥2。
比如表达式 ((a2b)2b)2a 表示字符串aabaabbaabaabba。
现在给你一个表达式,请统计一下其中各个字符出现的次数。
思路:很典型的递归处理,因为每次处理的字符串规则都是一样的,对于括号内的字符串,可以将它看成一个新字符串来递归处理.
坑点:oj的64位是真的坑,不小心用了个long long来用scanf转化输出字符就错了,建议大家在xtu oj上要么别用long long,要么用__int64,要么就不用scanf.
代码:
/***
* @Practice Win
* @打h_1,h_2
*/
#include
#pragma comment(linker, "/STACK:102400000,102400000")//解决递归函数多次调用栈溢出问题
using namespace std;
#define Debug(x) cout<<#x<<':'<<x<<endl
typedef long long ll;
#define INF 0x7fffffff//10^9级别,不到2^32
ll cnt[222];
string sr;
ll number(ll l,ll r){//将数字字符串转化为整数
ll ans=0;
for(ll i=l;i<r;i++){
ans=ans*10+sr[i]-'0';
}
return ans;
}
void solve(ll l,ll r,ll power){//递归处理,l是串起点,r是终点,power是串乘以的倍数
//关于power,因为括号后面可以接数字,表示几倍,所有需要power记录
for(ll i=l;i<r;i++){
if(sr[i]=='('){//如果是括号
ll t=1,p=i+1;
for(;p<r;p++){//找到这个括号对应的右括号位置
if(t==0) break;
if(sr[p]=='(') t++;
if(sr[p]==')') t--;
}
if(p<r && '1'<=sr[p] && sr[p]<='9'){//如果括号后面是数字
ll l_t=p,r_t=p+1;
while(r_t<r && '0'<=sr[r_t] && sr[r_t]<='9') r_t++;
solve(i+1,p-1,number(l_t,r_t)*power);
i=r_t-1;
}
else{//如果括号后面不是数字
solve(i+1,p-1,power);
i=p-1;
}
}
else{//如果是小写字母
if(i+1<r && '1'<=sr[i+1] && sr[i+1]<='9'){//如果字母后面是数字
ll l_t=i+1,r_t=i+2;
while(r_t<r && '0'<=sr[r_t] && sr[r_t]<='9') r_t++;
cnt[sr[i]]=cnt[sr[i]]+number(l_t,r_t)*power;
i=r_t-1;
}
else{//如果后面不是数字
cnt[sr[i]]=cnt[sr[i]]+power;
}
}
}
return ;
}
void init(){
memset(cnt,0,sizeof(cnt));//cnt数组初始化
}
void out(){//输出函数
for(char i='a';i<='z';i++){
if(cnt[i]==0) continue;
cout<<i<<" : "<<cnt[i]<<endl;
}
cout<<endl;
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
while(cin>>sr){
init();
solve(0,sr.length(),1);
out();
}
return 0;
}
头一次发现自己也能写出来这么好看的且规范的代码了,main函数里几个函数就搞定了(窃喜)