title: 5月8号补题
date: 2022-05-08 10:37:59
author: “胡耀文”
categories: “算法”
tags:
牛客小白月赛49_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
Dashboard - Codeforces Round #788 (Div. 2) - Codeforces
Dashboard - Codeforces Round #787 (Div. 3) - Codeforces
Dashboard - Codeforces Round #786 (Div. 3) - Codeforces
Dashboard - Codeforces Round #785 (Div. 2) - Codeforces
第 77 场双周赛 - 力扣(LeetCode) (leetcode-cn.com)
代码源 + cf + 牛客 + atcoder + 知乎严鸽哥
数字替换 - 题目 - Daimayuan Online Judge
#include
using namespace std;
const int N=5e5+10;
struct node{
int t,x,y;
}q[N];
int mp[N],n;
vector<int>ans;
signed main(){
for(int i=0;i<N;i++)mp[i]=i;
cin>>n;
for(int i=1;i<=n;i++){
int t,x,y;
cin>>t;
if(t==1){
cin>>x;
q[i]={t,x};
}
else{
cin>>x>>y;
q[i]={t,x,y};
}
}
for(int i=n;i>=1;i--){
int t=q[i].t;
int x=q[i].x;
int y=q[i].y;
if(t==2)mp[x]=mp[y];
else ans.push_back(mp[x]);
}
reverse(ans.begin(),ans.end());
for(auto x:ans)cout<<x<<" ";
}
画画 - 题目 - Daimayuan Online Judge
#include
using namespace std;
int n,m;
const int N=1100;
int a[N][N];
int get(int i,int j){
return (i-1)*m+j;
}
struct node{
int x,y,c;
}q[N*N];
int xx[]={-1,-1,1,0,1,2,2,2,1,0,1,0,1,2};
int yy[]={-1,0,0,-1,1,-1,0,1,0,1,1,2,2,2};
int dx[]={0,1,0,1};
int dy[]={0,0,1,1};
int check(int x,int y){
int p=-1;
for(int t=0;t<4;t++){
int i=x+dx[t];
int j=y+dy[t];
if(i<1||i>n||j<1||j>m)return 0;
int c=a[i][j];
if(c==-1)continue;
if(p==-1)p=c;
if(c!=p)return 0;
}
return 1;
}
int vis[N][N];
signed main(){
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cin>>a[i][j];
}
int hh=0,tt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(check(i,j)){
q[tt++]={i,j,a[i][j]};
vis[i][j]=1;
//cout<<"i="<}
}
}
if(hh==tt){
cout<<"-1";
return 0;
}
stack<node>ans;
while(hh<tt){
auto t=q[hh++];
ans.push(t);
int x=t.x,y=t.y,c=t.c;
a[x][y]=-1,a[x+1][y]=-1,a[x][y+1]=-1,a[x+1][y+1]=-1;
for(int t=0;t<14;t++){
int i=x+xx[t];
int j=y+yy[t];
if(i<1||i>n||j<1||j>m)continue;
if(vis[i][j])continue;
int c=-1;
//cout<<"i="<if(check(i,j)){
if(a[i][j]!=-1)c=a[i][j];
if(a[i+1][j]!=-1)c=a[i+1][j];
if(a[i][j+1]!=-1)c=a[i][j+1];
if(a[i+1][j+1]!=-1)c=a[i+1][j+1];
if(c==-1)c=1;
q[tt++]={i,j,c};
vis[i][j]=1;
//cout<<"i="<}
}
}
cout<<ans.size()<<'\n';
while(ans.size()){
auto t=ans.top();
ans.pop();
cout<<t.x<<" "<<t.y<<" "<<t.c<<'\n';
}
}
小雨坐地铁(分层图_牛客博客 (nowcoder.net)
环的数量 - 题目 - Daimayuan Online Judge
#include
using namespace std;
const int N=20,M=1<<N;
int f[M][N],n,m,g[N][N];
long long ans;
int lowbit(int x){return (int)log2(x&-x);}
int cal(int x){
int cnt=0;
while(x)cnt+=x&1,x>>=1;
return cnt;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
int mm=m;
while(m--){
int a,b;
cin>>a>>b;
a--,b--;
g[a][b]=g[b][a]=1;
//f[(1<
}
for(int i=0;i<n;i++)f[1<<i][i]=1;
for(int i=1;i<1<<n;i++){
int u=lowbit(i);
for(int j=0;j<n;j++){//j表示我现在走到了点集的哪个点上
if(!(i>>j&1))continue;
if(g[u][j])ans+=f[i][j];
for(int k=u+1;k<n;k++){//k表示我现在要走到哪个点
if(i>>k&1)continue;
if(!g[j][k])continue;
f[i|(1<<k)][k]+=f[i][j];
}
}
}
cout<<(ans-mm)/2;
}
最大权值划分 - 题目 - Daimayuan Online Judge
#include
using namespace std;
const int N=1e6+10;
#define int long long
int a[N],f[N][2],n;
signed main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=2;i<=n;i++){
if(a[i]<a[i-1]){
f[i][0]=max(f[i-1][0]+a[i-1]-a[i],f[i-1][1]);
f[i][1]=max(f[i-1][0],f[i-1][1]);
}
else{
f[i][1]=max(f[i-1][1]+a[i]-a[i-1],f[i-1][0]);
f[i][0]=max(f[i-1][1],f[i-1][0]);
}
}
cout<<max(f[n][0],f[n][1]);
}
Ayoub’s function - 题目 - Daimayuan Online Judge
组合数学+思维
(8条消息) Ayoub’s function CodeForces - 1301C(组合数学)_starlet_kiss的博客-CSDN博客
括号序列 - 题目 - Daimayuan Online Judge
#include
using namespace std;
string s;
const int N=1e6+10;
int f[N],match[N];
signed main(){
while(cin>>s){
memset(f,0,sizeof f);
stack<int>stk;
int n =s.length();
for(int i=1;i<=n;i++){
if(s[i-1]=='(')stk.push(i);
else{
if(stk.empty())continue;
else match[i]=stk.top(),stk.pop();
}
}
for(int i=1;i<=n;i++){
if(s[i-1]==')'&&match[i])f[i]=f[match[i]-1]+1;
}
// for(int i=1;i<=n;i++){
// if(s[i-1]=='(')stk.push(i);
// else{
// if(stk.empty())continue;
// int t=stk.top();
// stk.pop();
// match[t]=i;
// }
// }
// for(int i=n;i>=1;i--){
// f[i]=f[i-1];
// if(s[i-1]=='('&&match[i]!=0)f[i]=f[match[i]+1]+1;
// }
long long ans=0;
for(int i=1;i<=n;i++){
if(s[i-1]==')'&&match[i])ans+=f[i];
}
cout<<ans<<'\n';
}
}
弗拉德和糖果 II - 题目 - Daimayuan Online Judge
贪心+小思维
#include
#include
#include
using namespace std;
#define int long long
int sum,ma,n;
signed main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
sum+=x;
ma=max(ma,x);
}
if(ma-1>sum-ma)puts("NO");
else puts("YES");
}
任务分配 - 题目 - Daimayuan Online Judge
质区间长度 - 题目 - Daimayuan Online Judge
#include
using namespace std;
const int N=1e6+10;
int primes[N],cnt,st[N],l,r,k,a[N];
void init(){
st[1]=1;
for(int i=2;i<N;i++){
if(!st[i])primes[cnt++]=i;
for(int j=0;i*primes[j]<N;j++){
st[primes[j]*i]=1;
if(i%primes[j]==0)break;
}
}
}
int check(int mid){
for(int i=l;i<=r;i++){
int j=i+mid-1;
if(j>r)break;
if(a[j]-a[i-1]<k)return 0;
}
return 1;
}
signed main(){
init();
cin>>l>>r>>k;
for(int i=l;i<=r;i++){
if(!st[i])a[i]=a[i-1]+1;
else a[i]=a[i-1];
//cout<
}
if(a[r]-a[l-1]<k){
//cout<
cout<<"-1";
return 0;
}
int L=k,R=r-l+1;
while(L<R){
int mid=L+R>>1;
//cout<<"mid="<
if(check(mid))R=mid;
else L=mid+1;
}
cout<<max(1,R);
}
4009. 收集卡牌 - AcWing题库
#include
#include
#include
using namespace std;
const int N=16,M=1<<N;
int n,k;
double p[N],f[M][N*5+1];
double dfs(int x,int sum,int need){
if(f[x][sum]>=0)return f[x][sum];
if(sum>=need*k)return f[x][sum]=0;
f[x][sum]=0;
for(int i=0;i<n;i++){
if(x>>i&1)f[x][sum]+=p[i]*(dfs(x,sum+1,need)+1);
else f[x][sum]+=p[i]*(dfs(x^(1<<i),sum,need-1)+1);
}
return f[x][sum];
}
signed main(){
cin>>n>>k;
for(int i=0;i<n;i++)cin>>p[i];
memset(f,-1,sizeof f);
cout<<dfs(0,0,n);
}
1212. 地宫取宝 - AcWing题库
#include
#include
#include
using namespace std;
const int N = 55, MOD = 1000000007;
int n, m, k;
int w[N][N];
int f[N][N][13][14];
int main()
{
cin >> n >> m >> k;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
cin >> w[i][j];
w[i][j] ++ ;
}
f[1][1][1][w[1][1]] = 1;
f[1][1][0][0] = 1;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
if (i == 1 && j == 1) continue;
for (int u = 0; u <= k; u ++ )
for (int v = 0; v <= 13; v ++ )
{
int &val = f[i][j][u][v];
val = (val + f[i - 1][j][u][v]) % MOD;
val = (val + f[i][j - 1][u][v]) % MOD;
if (u > 0 && v == w[i][j])
{
for (int c = 0; c < v; c ++ )
{
val = (val + f[i - 1][j][u - 1][c]) % MOD;
val = (val + f[i][j - 1][u - 1][c]) % MOD;
}
}
}
}
int res = 0;
for (int i = 0; i <= 13; i ++ ) res = (res + f[n][m][k][i]) % MOD;
cout << res << endl;
return 0;
}
4381. 翻转树边 - AcWing题库
#include
using namespace std;
const int N = 2e5 + 10, M = 2 * N;
int h[N], ne[M], e[M], w[M], idx, dp[N];
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int f[N];
void dfs1(int u, int fa)
{
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i], k = w[i];
if (j == fa)
continue;
dfs1(j, u);
f[u] += f[j] + k;
}
}
void dfs2(int u, int fa)
{
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i], k = w[i];
if (j == fa)
continue;
dp[j] = dp[u] + (k == 1 ? 0 : 1) - (k == 1 ? 1 : 0);
dfs2(j, u);
}
}
int main()
{
int n;
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i < n; i++)
{
int a, b;
cin >> a >> b;
add(a, b, 0), add(b, a, 1);
}
dfs1(1, -1);
dp[1] = f[1];
dfs2(1, -1);
int mx = 0x3f3f3f3f;
for (int i = 1; i <= n; i++)
mx = min(mx, dp[i]);
cout << mx << "\n";
for (int i = 1; i <= n; i++)
if (dp[i] == mx)
cout << i << " ";
return 0;
}
3111. 回转寿司 - AcWing题库
值域树状数组,离散化后求值
#include
using namespace std;
#define int long long
const int N=3e5+10;
long long a[N],tr[N],n,L,R,ans,tot;
vector<long long>xs;
void add(int x,int c){
for(int i=x;i<N;i+=i&-i)tr[i]+=c;
}
long long sum(int x){
int ans=0;
for(int i=x;i;i-=i&-i)ans+=tr[i];
return ans;
}
int get(long long x){
return lower_bound(xs.begin(),xs.end(),x)-xs.begin()+1;
}
signed main(){
cin>>n>>L>>R;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]+=a[i-1];
}
for(int i=1;i<=n;i++){
xs.push_back(a[i]);
xs.push_back(a[i]-R-1);
xs.push_back(a[i]-L);
}
sort(xs.begin(),xs.end());
xs.erase(unique(xs.begin(),xs.end()),xs.end());
tot=xs.size();
add(get(a[0]),1);
for(int i=1;i<=n;i++){
int x=get(a[i]);
int y=get(a[i]-R-1);
int z=get(a[i]-L);
ans+=sum(z)-sum(y);
add(x,1);
}
cout<<ans;
}
4316. 合适数对 - AcWing题库
同方法题
2660. 方伯伯的玉米田 - AcWing题库
利用树状数组的dp
#include
#include
#include
using namespace std;
const int N=1e4+10,M=550;
int tr[M][N],a[N],n,k,ans;
void add(int k,int v,int c){
for(int i=k;i<=551;i+=i&-i){
for(int j=v;j<=5500;j+=j&-j){
tr[i][j]=max(tr[i][j],c);
}
}
}
int sum(int k,int v){
int ans=0;
for(int i=k;i;i-=i&-i){
for(int j=v;j;j-=j&-j){
ans=max(ans,tr[i][j]);
}
}
return ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=k;j>=0;j--){
int t=sum(j+1,a[i]+j)+1;
ans=max(ans,t);
add(j+1,a[i]+j,t);
}
}
cout<<ans;
}
AcWing 2978. 最长上升子序列 - AcWing
#include
using namespace std;
const int N=1e5+10;
vector<int>a;
int n,tr[N],dp[N];
void add(int x,int c){
for(int i=x;i<=n;i+=i&-i)tr[i]=max(tr[i],c);
}
int sum(int x){
int ans=0;
for(int i=x;i;i-=i&-i)ans=max(ans,tr[i]);
return ans;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
a.insert(x+a.begin(),i);
}
int ans=0;
for(int i=0;i<n;i++){
int t=a[i];
dp[t]=sum(t)+1;
add(t,dp[t]);
}
for(int i=1;i<=n;i++){
dp[i]=max(dp[i],dp[i-1]);
cout<<dp[i]<<'\n';
}
}
作者:我已经不想再做刺客了
链接:https://www.acwing.com/solution/content/105366/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1266. 校门外的树 - AcWing题库
很巧妙的思路
把区间想象成一条条线段
要求区间种数转化为求有多少个线段覆盖过这个区间
r之前的左端点数量减去l之前的右端点数量
#include
#include
#include
using namespace std;
const int N=1e5+10;
int n,m,l,r,t1[N],t2[N],op;
void add(int x,int tr[]){
for(int i=x;i<=n;i+=i&-i)tr[i]+=1;
}
int sum(int x,int tr[]){
int ans=0;
for(int i=x;i;i-=i&-i)ans+=tr[i];
return ans;
}
signed main(){
cin>>n>>m;
while(m--){
cin>>op>>l>>r;
if(op==1){
add(l,t1);
add(r,t2);
}
else{
cout<<sum(r,t1)-sum(l-1,t2)<<'\n';
}
}
}
2952. 不等式组 - AcWing题库
#include
#define endl '\n'
using namespace std;
const int N=2e6+10;
int n,t1[N],t2[N],ok,k[N],idx,vis[N],p[N];
void add(int tr[],int x,int c){
for(int i=x;i<N;i+=i&-i)tr[i]+=c;
}
int sum(int tr[],int x){
int ans=0;
for(int i=x;i;i-=i&-i)ans+=tr[i];
return ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
string s;
cin>>s;
if(s[0]=='A'){
int a,b,c;
cin>>a>>b>>c;
if(a==0){
if(b>c){
ok++;
k[++idx]=1;
}
else{
k[++idx]=0;
}
}
if(a>0){// k>x
int x=floor((1.0*c-b)/a);
if(x<-1e6){
ok++;
k[++idx]=1;
}
else if(x>1e6){
k[++idx]=0;
}
else{
add(t1,x+1e6+1,1);
k[++idx]=2;
p[idx]=x+1e6+1;
}
}
if(a<0){// k
int x=ceil((1.0*c-b)/a);
if(x>1e6){
ok++;
k[++idx]=1;
}
else if(x<-1e6){
k[++idx]=0;
}
else{
add(t2,x+1e6+1,1);
k[++idx]=3;
p[idx]=x+1e6+1;
}
}
}
if(s[0]=='Q'){
int x;
cin>>x;
x+=1e6+1;
int ans1=sum(t1,x-1);
int ans2=sum(t2,N-1)-sum(t2,x);
cout<<ans1+ans2+ok<<endl;
}
if(s[0]=='D'){
int x;
cin>>x;
if(vis[x])continue;
vis[x]=1;
if(k[x]==1)ok--;
if(k[x]==2)add(t1,p[x],-1);
if(k[x]==3)add(t2,p[x],-1);
}
}
}
4081. 选数 - AcWing题库
混合背包dp
#include
#include
#include
using namespace std;
const int N=220,M=200*26;
#define int long long
int f[N][M];
int n,k;
signed main(){
cin>>n>>k;
memset(f,-0x3f,sizeof f);
f[0][0]=0;
for(int i=1;i<=n;i++){
int a;
cin>>a;
int w=0;
int v=0;
while(a%5==0)a/=5,w++;
while(a%2==0)a/=2,v++;
//cout<
for(int j=k;j>=1;j--){
for(int t=M-1;t>=w;t--){
f[j][t]=max(f[j][t],f[j-1][t-w]+v);
}
}
}
int ans=0;
for(int i=1;i<M;i++)ans=max(ans,min(i,f[k][i]));
cout<<ans;
}
3281. 城市规划 - AcWing题库
树形dp 分组背包
#include
#include
#include
using namespace std;
const int N = 5e4+10,M=2*N;
const long long INF=0x3f3f3f3f3f3f3f3f;
int h[N],ne[M],e[M],idx,n,m,K;
int s[N];
int st[N];
long long w[M];
long long f[N][110];//f【u】【k】表示以u为根选k个点的最大值
long long ans=INF;
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa){
f[u][0]=0;
if(st[u])f[u][1]=0,s[u]=1;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==fa)continue;
dfs(j,u);
s[u]+=s[j];
for(int k=min(s[u],K);k>=0;k--){
for(int x=0;x<=min(k,s[j]);x++)
f[u][k]=min(f[u][k],f[u][k-x]+f[j][x]+w[i]*x*(K-x));
}
}
ans=min(ans,f[u][K]);
}
signed main(){
memset(h, -1, sizeof h);
cin>>n>>m>>K;
while(m--){
int x;
scanf("%d",&x);
st[x]=1;
}
for(int i=1;i<n;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
// for(int i=0;i
// for(int j=0;j<110;j++){
// f[i][j]=0x3f3f3f3f;
// }
// }
memset(f,0x3f3f,sizeof f);
dfs(1,-1);
cout<<ans;
}
E-禅_牛客小白月赛49 (nowcoder.com)
思维递推
从起点p向两边递推,考虑每个单调区间,这种做法是错误的
比如2 2 2 2 1 10 0
从最左边开始代价是最小的,会一直加
那么既然无法确定起点,如何处理这n方复杂度?
设dp【i】表示从点i开始的代价,考虑答案之间的递推关系
#include
using namespace std;
#define int long long
const int N=1e5+10;
int n,a[N],T,f[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--){
cin>>n;
int p;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==0)p=i;
}
if(n==1){
cout<<"No Solution"<<'\n';
continue;
}
for(int i=1;i<=n;i++)f[i]=0;
f[p-1]=a[p-1]+1;
f[p+1]=a[p+1]+1;
for(int i=p+2;i<=n;i++)f[i]=max(a[i]+1,f[i-1]-a[i]);
for(int i=p-2;i>=1;i--)f[i]=max(a[i]+1,f[i+1]-a[i]);
int ans=1e9;
for(int i=1;i<=n;i++){
if(i==p)continue;
ans=min(ans,f[i]);
}
cout<<ans<<'\n';
}
}