题目链接
说实话,这些题或多或少的做过,或者补过,稍微想想就想到了做法。
A-小A买彩票
做法:dp,设dp[i][j]为前i个数,得到的金额为j,
dp方程:
rep(j,1,4){
for(int k=10;k<=200;++k)
dp[i][k+j-3]+=dp[i-1][k];
}由于可能会减到负数,所以对所有状态移动到一个比较大的数即可。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int maxn=1e2+10,N=1e2;
ll dp[N][N*N],n;
int main()
{
n=read();
dp[0][N]=1;
rep(i,1,n){
rep(j,1,4){
for(int k=10;k<=200;++k)
dp[i][k+j-3]+=dp[i-1][k];
}
}
ll fz=0;
for(int i=N;i<=200;++i) fz=fz+dp[n][i];
ll fm=1ll<<(n*2);
//printf("fz:%lld fm:%lld\n",fz,fm);
ll gc=gcd(fz,fm);
fz/=gc,fm/=gc;
printf("%lld/%lld\n",fz,fm);
}
B-「金」点石成金
做法:n只有15,暴力dfs即可
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=20;
ll a[N],b[N],c[N],d[N],ans;
int n;
void dfs(int id,ll mofa,ll money)
{
if(id>n){
ans=max(ans,mofa*money);
return ;
}
dfs(id+1,max(0ll,mofa-b[id]),money+a[id]);
dfs(id+1,mofa+c[id],max(0ll,money-d[id]));
}
int main()
{
n=read();
rep(i,1,n)
{
a[i]=read();
b[i]=read();
c[i]=read();
d[i]=read();
}
ans=-1e18;
dfs(1,0,0);
printf("%lld\n",ans);
}
C-小阳的贝壳
做法:线段树维护差分数组,之前写过博客:博客
#include<bits/stdc++.h>
using namespace std;
#define ls id<<1
#define rs id<<1|1
const int N=1e5+10;
int gcd[N*4],mx[N*4],mi[N*4],T[N*4],n,m,a[N];
void up(int id,int l,int r,int pos,int val)
{
if(l==r)
{
mx[id]+=val;
mi[id]=gcd[id]=mx[id];
gcd[id]=abs(gcd[id]);
return ;
}
int mid=l+r>>1;
if(pos<=mid)up(ls,l,mid,pos,val);
else up(rs,mid+1,r,pos,val);
mx[id]=max(mx[ls],mx[rs]);
mi[id]=min(mi[ls],mi[rs]);
gcd[id]=__gcd(gcd[ls],gcd[rs]);
}
void up2(int id,int l,int r,int ql,int qr,int v)
{
if(ql<=l&&r<=qr){
T[id]+=v;
return;
}
int mid=l+r>>1;
if(ql<=mid) up2(ls,l,mid,ql,qr,v);
if(qr>mid) up2(rs,mid+1,r,ql,qr,v);
}
int qu2(int id,int l,int r,int pos)
{
if(l==r) return T[id];
int res=T[id];
int mid=l+r>>1;
if(pos<=mid) res+=qu2(ls,l,mid,pos);
else res+=qu2(rs,mid+1,r,pos);
return res;
}
int qu(int id,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr){
return max(abs(mx[id]),abs(mi[id]));
}
int mid=l+r>>1;
int res=0;
if(ql<=mid) res=max(res,qu(ls,l,mid,ql,qr));
if(qr>mid) res=max(res,qu(rs,mid+1,r,ql,qr));
return res;
}
int qugcd(int id,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return gcd[id];
int mid=l+r>>1;
if(qr<=mid) return qugcd(ls,l,mid,ql,qr);
else if(ql>mid) return qugcd(rs,mid+1,r,ql,qr);
else{
int t1=qugcd(ls,l,mid,ql,qr);
int t2=qugcd(rs,mid+1,r,ql,qr);
return __gcd(t1,t2);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
up(1,1,n,i,a[i]-a[i-1]);
up2(1,1,n,i,i,a[i]);
}
int ans;
while(m--){
int ty,l,r;
scanf("%d%d%d",&ty,&l,&r);
if(ty==1){
int x;
scanf("%d",&x);
up(1,1,n,l,x);
if(r+1<=n) up(1,1,n,r+1,-x);
up2(1,1,n,l,r,x);
}
else if(ty==2){
if(l==r) printf("0\n");
else{
ans=qu(1,1,n,l+1,r);//因为是差分数组,所以l要加1
printf("%d\n",ans);
}
}
else{
int v=qu2(1,1,n,l);
if(l==r) printf("%d\n",v);
else{
int gc=qugcd(1,1,n,l+1,r);
printf("%d\n",__gcd(gc,v));//左端点的值gcd上差分数组内的gcd
}
}
}
}
D-Forsaken喜欢字符串
做法:由于k很小,hash即可 map预处理hash。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+10;
ll base[3]={43,47};
ll h[3][N][10];
ll mod[3]={1000000007,998244353};
ll f[3][N];
int n,k;
const int M=5e4+10;
char s[M][10];
map<pair<int,int>,int>mp;
void init()
{
f[0][0]=1;
f[1][0]=1;
for(int i=1;i<N;++i)
{
for(int j=0;j<2;++j) f[j][i]=f[j][i-1]*base[j]%mod[j];
}
}
pair<int,int> getv(int id,int l,int r)
{
pair<int,int>p;
int d1=(h[0][id][r]-h[0][id][l-1]*f[0][r-l+1]%mod[0]+mod[0])%mod[0];
int d2=(h[1][id][r]-h[1][id][l-1]*f[1][r-l+1]%mod[1]+mod[1])%mod[1];
p=make_pair(d1,d2);
return p;
}
int getid(char c)
{
return c-'0';
}
int main()
{
init();
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
{
scanf("%s",s[i]+1);
for(int j=1;j<=k;++j)
{
for(int k=0;k<2;++k)
{
h[k][i][j]=h[k][i][j-1]*base[k]%mod[k]+getid(s[i][j]);
}
}
for(int r=1;r<=k;++r)
{
for(int l=1;l<=r;++l)
{
pair<int,int>p;
p=getv(i,l,r);
mp[p]++;
}
}
}
int q;
scanf("%d",&q);
while(q--)
{
int id,len;
ll ans=0;
scanf("%d%d",&id,&len);
for(int r=1;r<=k;++r)
{
for(int l=1;l<=r;++l)
{
pair<int,int>p;
p=getv(id,l,r);
mp[p]--;
}
}
for(int i=1;i+len-1<=k;++i)
{
pair<int,int>p;
p=getv(id,i,i+len-1);
//printf("l:%d r:%d mp:%d\n",i,i+len-1,mp[p]);
ans+=1ll*mp[p]*len;
}
for(int r=1;r<=k;++r)
{
for(int l=1;l<=r;++l)
{
pair<int,int>p;
p=getv(id,l,r);
mp[p]++;
}
}
printf("%lld\n",ans);
}
}
/*
3 4
abab
abab
abab
100
3 1
*/
E-Board
做法:找出每行每列的最小值,然后每行每列减去这个最小值,-1的位置就加上这个最小值即可。枚举完毕-1位置加的数就是答案。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=1e3+10;
int a[N][N],n,ans[N][N];
int main()
{
n=read();
rep(i,1,n) rep(j,1,n) a[i][j]=read();
rep(i,1,n)
{
int mi=1e9;
rep(j,1,n)
{
if(a[i][j]==-1) continue;
mi=min(mi,a[i][j]);
}
if(mi==1e9) continue;
rep(j,1,n){
if(a[i][j]==-1) ans[i][j]+=mi;
else a[i][j]-=mi;
}
}
rep(j,1,n)
{
int mi=1e9;
rep(i,1,n)
{
if(a[i][j]==-1) continue;
mi=min(mi,a[i][j]);
}
if(mi==1e9) continue;
rep(i,1,n)
{
if(a[i][j]==-1) ans[i][j]+=mi;
else a[i][j]-=mi;
}
}
rep(i,1,n)
{
rep(j,1,n)
{
if(a[i][j]==-1){
printf("%d\n",ans[i][j]);
return 0;
}
}
}
}