eg:題目難度感覺是升序的啊,又是一場七題(然後又沒打完,跑去和同學英雄聯盟了),沒想到I題隻是個小貪心,H題樹狀數組和J題确實不太會,簡單的記錄一下通過的前七道題,最後三道題如果補了的話會更新的。
A-歐幾裡得
題意:輾轉相除法進行了n次,求最小的a+b且a>b。
題解:随意觀察了一下,可以發現是個斐波那契數列從 0 , 1 , 2 , 3 , 5 , 8 … … 0,1,2,3,5,8…… 0,1,2,3,5,8……若n為0則是0+1,若n為1則是1+2,類推。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
ll f[100];
int main(){
f[0]=0;f[1]=1;f[2]=2;
for(int i=3;i<=81;i++)f[i]=f[i-1]+f[i-2];
int T;
scanf("%d",&T);
while(T--){
int i;
scanf("%d",&i);
printf("%lld\n",f[i]+f[i+1]);
}
return 0;
}
B-括号序列
題意:括号序列判斷是否合法。
題解:棧的基礎應用,似乎會爆系統棧(或者我系統棧寫萎了)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
char s[maxn];
char q[maxn];
int cnt;
int main(){
scanf("%s",&s);
int len=strlen(s),flag=0;
for(int i=0;i<len;i++){
if(s[i]=='(' || s[i]=='[' || s[i]=='{')q[++cnt]=s[i];
else{
if(s[i]==')'){
if(q[cnt]=='(')cnt--;
else flag=1;
}
if(s[i]==']'){
if(q[cnt]=='[')cnt--;
else flag=1;
}
if(s[i]=='}'){
if(q[cnt]=='{')cnt--;
else flag=1;
}
}
}
if(cnt!=0)flag=1;
if(!flag)puts("Yes");
else puts("No");
return 0;
}
C-子段乘積
題意:長度為n的數組,求連續k個數的乘積的最大值。
題解:線段樹維護區間乘法。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int mod=998244353;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,k,a[maxn];
ll s[maxn*4];
void pushup(int node){
s[node]=s[node<<1]*s[node<<1|1]%mod;
}
void build(int node,int l,int r){
if(l==r){
s[node]=1ll*a[l];
return;
}
int mid=(l+r)>>1;
build(node<<1,l,mid);
build(node<<1|1,mid+1,r);
pushup(node);
}
ll query(int L,int R,int l,int r,int node){
if(L<=l && r<=R)return s[node];
int mid=(l+r)>>1;
ll ans=1;
if(L<=mid)ans=ans*query(L,R,l,mid,node<<1)%mod;
if(R>mid)ans=ans*query(L,R,mid+1,r,node<<1|1)%mod;
return ans;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
int l=1,r=k;
ll ans=0;
while(r<=n){
ans=max(ans,query(l,r,1,n,1));
l++;r++;
}
printf("%lld\n",ans);
return 0;
}
D-子段異或
題意:長度為n的數組,求區間異或和為0的數量。
題解:維護區間字首異或和,如果兩個異或和的值相等說明這個區間異或和為0。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int mod=998244353;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,a[maxn],f[maxn];
map<int,int>mmap;
ll ans;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)f[i]=f[i-1]^a[i];
for(int i=0;i<=n;i++)
ans+=1ll*mmap[f[i]],mmap[f[i]]++;
printf("%lld\n",ans);
return 0;
}
E-最小表達式
題意:給出若幹個1~9還有+号,問如何排列組合使得可以排列出一個合法的加法算式且結果最小。
題解:貪心,盡可能均勻配置設定數字即可。注意需要用到高精度。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int a[11],k,num;
char s[maxn];
string A[maxn],ans,v;
string add(string a,string b){
v.clear();
int tmp=0,t=0;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
while(a.size()!=b.size()){
if(a.size()>b.size())b.push_back('0');
else a.push_back('0');
}
for(int i=0;i<a.size();i++){
tmp=a[i]+b[i]-'0'*2+t;
t=tmp/10;
v.push_back(tmp%10+'0');
}
if(t>0)v.push_back(t+'0');
reverse(v.begin(),v.end());
return v;
}
int main(){
scanf("%s",&s);
int len=strlen(s);
for(int i=0;i<len;i++)
if(s[i]=='+')k++;
else a[s[i]-'0']++,num++;
if(k==0){
sort(s,s+len);
printf("%s\n",s);
}
else{
int l=1;
for(int i=1;i<=9;i++){
for(int j=1;j<=a[i];j++){
A[l].push_back(i+'0');
l++;
if(l>k+1)l=1;
}
}
for(int i=1;i<=k+1;i++)
ans=add(A[i],ans);
cout<<ans<<endl;
}
return 0;
}
F-樹上博弈
題意:給出一棵樹,每次隻能選擇朝葉子結點或者父親結點移動,如果不能移動則對方獲勝。問先手獲勝的雙方起始狀态數量。
題解:觀察到,如果雙方距離為偶數時先手必勝。那麼轉換成樹上求距離為偶數的點對。樹上dp入門題。考慮 d p [ u ] [ 0 ] dp[u][0] dp[u][0]為到u結點的偶數結點數, d p [ u ] [ 1 ] dp[u][1] dp[u][1]為到u結點的奇數結點數,周遊這棵樹,to表示可到達的結點,每個結點的答案就是 d p [ u ] [ 0 ] ∗ d p [ t o ] [ 1 ] + d p [ u ] [ 1 ] ∗ d p [ t o ] [ 0 ] dp[u][0]*dp[to][1]+d p[u][1]*dp[to][0] dp[u][0]∗dp[to][1]+dp[u][1]∗dp[to][0],每次還需要更新 d p [ u ] [ 0 ] dp[u][0] dp[u][0]和 d p [ u ] [ 1 ] dp[u][1] dp[u][1]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
int read(){
int f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n;
ll dp[maxn][2],ans;
vector<int>G[maxn];
inline void dfs(int u,int fa){
dp[u][0]=1ll;dp[u][1]=0ll;
for(int i=0;i<G[u].size();i++){
int to=G[u][i];
if(to==fa)continue;
dfs(to,u);
ans+=dp[u][0]*dp[to][1];
ans+=dp[u][1]*dp[to][0];
dp[u][0]+=dp[to][1];
dp[u][1]+=dp[to][0];
}
}
int main(){
n=read();
for(int i=2;i<=n;i++){
int x;
x=read();
G[x].push_back(i);
G[i].push_back(x);
}
ans=0;
dfs(1,-1);
printf("%lld\n",ans*2ll);
return 0;
}
G-音樂鑒賞
題意:不怎麼好說,看題了解吧。
題解:二分答案,二分這個期末占比。check僅需保證每個人的平均分乘上平均分占比加上81*期末占比大于90即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n;
double ans,a[maxn];
bool check(double x){
if(ans*(1.0-x)+81*x>90)return true;
else return false;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lf",&a[i]),ans+=a[i];
ans/=n;
double l=0.0,r=1.0,mid,f;
while(fabs(l-r)>=eps){
mid=(l+r)/2;
if(check(mid))l=mid,f=l;
else r=mid;
}
f*=100;
printf("%.2lf%%\n",f);
return 0;
}
剛剛補了道I題前來更新
I-比對星星
題意:給出了n個星星,每個星星有橫縱坐标還有一個價值z,如果 x i < x j , y i < y j , z i < z j x_i<x_j ,y_i<y_j,z_i<z_j xi<xj,yi<yj,zi<zj那麼就能比對,要盡可能多的比對。求數量。
題解:z的取值是0和1,是以題目就成了一道水題。先按照x坐标排序如果z為0就加入待比對序列,為1就開始比對,找到一個滿足題意的盡可能大的y即可。用muliset維護(STL大出彩)。
#include "stdio.h"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "stack"
#include "set"
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
int n,ans;
struct arr{
int x,y,z;
}p[maxn];
multiset<int>s;
multiset<int>::iterator it;
bool cmp(arr a,arr b){
return a.x<b.x;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
sort(p+1,p+1+n,cmp);
for(int i=1;i<=n;i++){
if(p[i].z==0)s.insert(p[i].y);
else{
it=s.lower_bound(p[i].y);
if(it!=s.begin()){
it--;
s.erase(it);ans++;
}
}
}
printf("%d\n",ans);
return 0;
}