C:刷题统计
先把整周的除掉,剩下看到一周的星期几
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define mod 1000000007
using namespace std;
int n,m,k,ans;
int a,b;
void solve(){
cin>>n>>a>>b;
ans=n/(5*a+2*b);
n%=(5*a+2*b);
for(int i=1;i<=5;i++){
if(n>0) {n-=a;ans++;}
}
if(n>0){n-=b;ans++;}
if(n>0){n-=b;ans++;}
cout<<ans;
}
signed main(){
int _=1;
//cin>>_;
while(_--)
solve();
}
D:修剪灌木
对每个 i i i,可以知道答案为 2 ∗ m a x ( n − i , i − 1 ) 2*max(n-i,i-1) 2∗max(n−i,i−1),代码略。
E:X 进制减法
考虑到每点权值是其低位进制的后缀积,而又因为 A > B A>B A>B所以只需要尽可能地使各位上进制小即可,直接 m a x ( 2 , a [ i ] + 1 , b [ i ] + 1 ) max({2,a[i]+1,b[i]+1}) max(2,a[i]+1,b[i]+1)即可(max套max写法是赛场上担心编译不通过。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define mod 1000000007
using namespace std;
int n,m,k,ans;
int a[200005],b[200005],c[200005];
void solve(){
cin>>k>>n;ans=0;
for(int i=1;i<=n;i++){cin>>a[i];}
cin>>m;
for(int i=n-m+1;i<=n;i++){cin>>b[i];}
for(int i=1;i<=n;i++){c[i]=max(1ll,max(a[i],b[i]))+1;}
int res=1;
for(int i=n;i;i--){
ans=(ans+mod+res*(a[i]-b[i])%mod)%mod;
res=res*c[i]%mod;
}
cout<<ans;
}
signed main(){
int _=1;
//cin>>_;
while(_--)
solve();
}
F: 统计子矩阵
解法一:枚举左右边界,上下边界通过双指针确定,复杂度 O ( N 3 ) O(N^3) O(N3)
解法二(我赛时的写法):首先考虑 n 4 n^4 n4做法,即枚举矩形的一个对角线,令对角线坐标为 ( x i , y i ) ( x j , y j ) 且 x j < x i , y j < y i (x_i,y_i)(x_j,y_j) 且x_j<x_i,y_j<y_i (xi,yi)(xj,yj)且xj<xi,yj<yi容易发现当 ( x i , y i ) (x_i,y_i) (xi,yi)确定时,随着 y j y_j yj的上升满足条件最小的 x i x_i xi下降,这里可用双指针维护。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define mod 1000000007
using namespace std;
int n,m,k,ans,qaq;
int a[505][505],sum[505][505];
int qpow(int x,int y,int res=1){
for(;y;y>>=1,(x*=x)%=mod) if(y&1) (res*=x)%=mod;
return res;
}
void solve(){
ans=0;
cin>>n>>m>>qaq;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=1,t=j;k<=i;k++){
while(t&&sum[i][j]-sum[k-1][j]-sum[i][t-1]+sum[k-1][t-1]<=qaq){
t--;
}
ans+=j-t;
//cout<<i<<" "<<j<<" "<<k<<" "<<t<<" "<<ans<<endl;
}
}
}
cout<<ans;
}
signed main(){
int _=1;
//cin>>_;
while(_--)
solve();
}
G: 积木画
一个挺基础的dp,大概意思是 d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示恰好构成一个 2 ∗ i 2*i 2∗i的矩形,而 d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示离构成一个 2 ∗ i 2*i 2∗i的矩形还差一格。模拟一下容易得到以下代码中式子。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define mod 1000000007
using namespace std;
int n,m,k,ans,qaq;
int dp[10000006][2];
void solve(){
cin>>n;
dp[1][0]=1,dp[2][0]=2;
dp[2][1]=2;
for(int i=3;i<=n;i++){
dp[i][0]=(dp[i-1][1]+dp[i-1][0]+dp[i-2][0])%mod;
dp[i][1]=(dp[i-1][1]+dp[i-2][0]*2)%mod;
}
cout<<dp[n][0]<<endl;
}
signed main(){
int _=1;
cin>>_;
while(_--)
solve();
}
H:扫雷
这题赛时读假了写的代码错的,以后再补吧。
I: 李白打酒加强版
又是一个dp,
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示经过i个酒店和j朵花剩k的酒的方案数,在每一点可以选择进酒店或者碰到花,直接三重循环即可。
最后输出
d
p
[
n
]
[
m
]
[
0
]
dp[n][m][0]
dp[n][m][0]即可
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define mod 1000000007
using namespace std;
int n,m,k,ans,qaq;
int dp[106][105][105];
void solve(){
cin>>n>>m;
dp[0][0][2]=1;
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=1;k<=m;k++){
if(k*2<=m)(dp[i+1][j][k*2]+=dp[i][j][k])%=mod;
(dp[i][j+1][k-1]+=dp[i][j][k])%=mod;
}
}
}
cout<<dp[n][m][0];
}
signed main(){
int _=1;
//cin>>_;
while(_--)
solve();
}
J: 砍竹子
首先容易发现同一个点至多开6次根号。
其次容易发现每次砍当前最高点一定不会比其余情况更劣,所以使用优先队列模拟即可。
开根号要自己重新手写,不然会炸精度,赛时代码没写不知道烂多少。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define mod 1000000007
using namespace std;
int n,m,k,ans,qaq;
int a[200005];
struct node{
int x,l,r;
bool operator <(const node &t) const {
return x<t.x||x==t.x&&l>t.l;
}
};
priority_queue<node>q;
void solve(){
ans=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
node t={a[i],i,i};
if(a[i]!=1)q.push(t);
}
while(!q.empty()){
node u=q.top();
q.pop();
while(!q.empty()){
node v=q.top();
if(u.x==v.x&&v.l==u.r+1){
u.r=v.r;
q.pop();
}
else{
break;
}
}
ans++;
u.x=sqrt(u.x/2+1);
if(u.x!=1){
q.push(u);
}
}
cout<<ans;
}
signed main(){
int _=1;
//cin>>_;
while(_--)
solve();
}