完全不会数据结构就比较离谱
Another One
A - Roadblock
Problem Link
题意
FJ的农场由 N N N个点 M M M条边组成,边存在边权
它每次都会沿着最短路径从点 1 1 1走到点 N N N
现在FJ的牛想选择这张图中的任意一条边,使其边权翻倍
问选择某条边翻倍后,FJ需要多走的距离的最大值是多少(最短路的最大增量)
标签
Dijkstra
SPFA
思路
先在原图中跑一遍SPFA,求出此时的最短路长度 o r i g i n a l D i s t a n c e originalDistance originalDistance并且回溯得到这条路的每一条边
因为只有把最短路上的边翻倍,FJ才有可能走更长的路
所以枚举这条路上的每一条边,翻倍后尝试再跑一遍最短路(这里推荐用Dijkstra),求出此时的最短路长度 c u r r e n t D i s t a n c e currentDistance currentDistance
答案就是 c u r r e n t D i s t a n c e − o r i g i n a l D i s t a n c e currentDistance-originalDistance currentDistance−originalDistance的最大值
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;int n,m;
vector<P> G[105];
int dis[105];
int pre[105];
vector<P> edge;int curu,curv;void spfa()
{queue<int> q;mst(dis,INF);dis[1]=0;q.push(1);while(!q.empty()){int u=q.front();q.pop();for(P pd:G[u]){int v=pd.first,w=pd.second;if(dis[v]>dis[u]+w){dis[v]=dis[u]+w;q.push(v);pre[v]=u;}}}int pos=n;while(pos!=1){edge.pb(P(pos,pre[pos]));pos=pre[pos];}
}void dijkstra()
{priority_queue<P> pq;mst(dis,INF);dis[1]=0;pq.push(P(0,1));while(!pq.empty()){P pp=pq.top();pq.pop();int u=pp.second;if(dis[u]!=-pp.first)continue;for(P pd:G[u]){int v=pd.first,w=pd.second;if(u==curu&&v==curv||u==curv&&v==curu)w<<=1;if(dis[u]+w<dis[v]){dis[v]=dis[u]+w;pq.push(P(-dis[v],v));}}}
}void solve()
{cin>>n>>m;rep(i,1,m){int a,b,c;cin>>a>>b>>c;G[a].pb(P(b,c));G[b].pb(P(a,c));}spfa();int curans=dis[n];int maxans=0;for(P p:edge){curu=p.first;curv=p.second;dijkstra();maxans=max(maxans,dis[n]);}cout<<maxans-curans<<'\n';
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}
B - Grass Planting
Problem Link
题意
FJ有张 N N N个点 N − 1 N-1 N−1条边的树图
初始时每条边的边权为 0 0 0
有两种操作:
P P P操作会把 u u u到 v v v的最短路径上的每条边边权 + 1 +1 +1
Q Q Q操作则会询问某条边的边权(保证询问的两个点是相邻的)
标签
Segment Tree
LCA
DFS Clock
思路
暂无,等想好了再改
或者建议直接问余总
代码
//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
#include<bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
#define all(a) (a).begin(),(a).end()
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
using namespace std;
//using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-12;
const double PI=acos(-1.0);
const ll mod=998244353;
const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}int n;const int MAXN=100050,MAXF=18;vector<int> G[MAXN];
int depth[MAXN];
int father[MAXN][MAXF];
bool vis[MAXN];int lll[MAXN],rrr[MAXN],sz[MAXN];
int clk=0;void dfs(int pos,int fa)
{vis[pos]=true;depth[pos]=depth[fa]+1;father[pos][0]=fa;for(int i=1;i<MAXF;i++)father[pos][i]=father[father[pos][i-1]][i-1];int cnt=G[pos].size();lll[pos]=++clk;sz[pos]=1;for(int i=0;i<cnt;i++){if(!vis[G[pos][i]]){dfs(G[pos][i],pos);sz[pos]+=sz[G[pos][i]];}}rrr[pos]=lll[pos]+sz[pos]-1;
}int lca(int a,int b)
{while(depth[a]<depth[b]){for(int i=MAXF-1;i>=0;i--){if(depth[b]-(1<<i)>=depth[a])b=father[b][i];}}while(depth[a]>depth[b]){for(int i=MAXF-1;i>=0;i--){if(depth[a]-(1<<i)>=depth[b])a=father[a][i];}}if(a==b)return a;while(father[a][0]!=father[b][0]){for(int i=MAXF-1;i>=0;i--){if(father[a][i]!=father[b][i]){a=father[a][i];b=father[b][i];}}}return father[a][0];
}struct node
{int l,r;ll sum,lazy;
}tree[MAXN*4];void push_up(int id)
{tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}void push_down(int id)
{if(tree[id].lazy){int m=tree[id].r-tree[id].l+1;tree[id<<1].lazy+=tree[id].lazy;tree[id<<1|1].lazy+=tree[id].lazy;tree[id<<1].sum+=tree[id].lazy*(m-(m>>1));tree[id<<1|1].sum+=tree[id].lazy*(m>>1);tree[id].lazy=0;}
}void buildTree(int id,int l,int r)
{tree[id].l=l;tree[id].r=r;tree[id].lazy=0;if(l==r){tree[id].sum=0;return;}int mid=(l+r)>>1;buildTree(id<<1,l,mid);buildTree(id<<1|1,mid+1,r);push_up(id);
}void update(int id,int L,int R,ll val)
{if(L<=tree[id].l&&R>=tree[id].r){tree[id].sum+=val*(tree[id].r-tree[id].l+1);tree[id].lazy+=val;return;}push_down(id);int mid=(tree[id].r+tree[id].l)>>1;if(L<=mid)update(id<<1,L,R,val);if(R>mid)update(id<<1|1,L,R,val);push_up(id);
}ll query_sum(int id,int L,int R)
{if(L<=tree[id].l&&R>=tree[id].r)return tree[id].sum;push_down(id);int mid=(tree[id].r+tree[id].l)>>1;ll ans=0;if(L<=mid)ans+=query_sum(id<<1,L,R);if(R>mid)ans+=query_sum(id<<1|1,L,R);return ans;
}void solve()
{int q;cin>>n>>q;repp(i,1,n){int a,b;cin>>a>>b;G[a].pb(b);G[b].pb(a);}dfs(1,0);buildTree(1,1,n);while(q--){string op;cin>>op;if(op=="P"){int u,v;cin>>u>>v;int z=lca(u,v);update(1,lll[u],lll[u],1);update(1,lll[v],lll[v],1);update(1,lll[z],lll[z],-2);}else{int u,v;cin>>u>>v;if(depth[u]<depth[v])swap(u,v);cout<<query_sum(1,lll[u],rrr[u])<<'\n';}}
}
int main()
{closeSync;//multiCase{solve();}return 0;
}
C - Hay Bales
Problem Link
标签
Implementation
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;int a[10010];void solve()
{int n,s=0;cin>>n;rep(i,1,n){cin>>a[i];s+=a[i];}s/=n;int r=0;rep(i,1,n)r+=max(a[i]-s,0);cout<<r<<'\n';
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}
D - Cow Photography II
Problem Link
E - Cow Photography I
Problem Link
题意
两道题大致意思相同,直接讲Hard版本
FJ会按某一种顺序让 N N N头牛排成一队照相
但每次在照相前,总会有一些牛会走出队列,然后随意插入队列中的某些位置
FJ就这样拍了 5 5 5张照,每次拍照后都会再让所有牛按原先安排的顺序排回去
现在只知道,对于每一头牛,在这 5 5 5张照片中它只会主动走到其他位置一次,剩余四张在拍照时不会主动移动(也可能 5 5 5张照片中都不走动)
试根据这 5 5 5张照片判断出原先安排的顺序是什么
标签
Sorting
(Hard Version) Hashing
思路
首先抓住题目的要点,也就是 5 5 5张照片中每头牛最多主动走到其他位置一次
也就是说,对于任意的两头牛 a , b a,b a,b,一开始 a a a排在 b b b前面
某一次照相中 a a a主动走到 b b b后面
另一次照相中 b b b主动走到 a a a前面
这两次照相 a , b a,b a,b的顺序和原先是不同的
但是其他三次照相都是按照原先顺序不会改变
所以可以通过牛的 i d id id反标记其原来的位置,可以利用Hash方法(map/unordered_map/gp_hash_table等)来记录
- 利用 p o s [ i ] [ j ] pos[i][j] pos[i][j]表示在第 i i i次照相中,id为 j j j的牛的位置
那么在确定最终的顺序时,如果想要判断任意两头牛 a , b a,b a,b的顺序是怎样的,只需要检查在 5 5 5次照相中, a a a排在 b b b前面的次数多还是反之
但是由于 N = 20000 N=20000 N=20000,无法根据拓扑排序建图来获得答案
但可以根据快速排序 O ( n log n ) O(n\log n) O(nlogn)的时间复杂度,重写id的判定规则来实现
总时间复杂度为 O ( n log n log n ) O(n\log n\log n) O(nlognlogn),使用unordered_map或gp_hash_table时可以优化成常数较大的 O ( n log n ) O(n\log n) O(nlogn)
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;int n;
int a[5][20010];
unordered_map<int,int> pos[5];struct node
{int id;bool operator < (const node& a) const{int l=0,r=0;repp(t,0,5){if(pos[t][id]<pos[t][a.id])l++;elser++;}return l>r;}
}ar[20010];void solve()
{cin>>n;repp(t,0,5){rep(i,1,n){cin>>a[t][i];pos[t][a[t][i]]=i; //id反记录位置}}rep(i,1,n)ar[i].id=a[0][i];sort(ar+1,ar+n+1);rep(i,1,n)cout<<ar[i].id<<'\n';
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}
F - Simplifying the Farm
Problem Link
题意
N N N个点 M M M条边的图
要求求出最小生成树的路径权值和,以及不同的最小生成树的种类数
已知同样长度的边最多不超过 3 3 3条
标签
Minimum Spanning Tree : Kruskal
Counting & Implementation
思路
(是最暴力的分类讨论实现)
最小生成树计数的矩阵数原理不适用于本题中这样的大数据
但题目给出了一条关键限制——同样长度的边最多不超过 3 3 3条
并且数据范围中每条边的长度限制在 1 0 6 10^6 106以内
所以可以开一个 1 0 6 10^6 106大小的 vector<int> eg[i] 来记录长度为 i i i的边有哪些
根据最小生成树的 K r u s k a l Kruskal Kruskal算法,将边按照从小到大排序后,如果某条边两端的点处于不同的集合内,就将其加入最小生成树中,贡献是将图中独立的集合 − 1 -1 −1
可以从 1 1 1到 1 0 6 10^6 106枚举长度,忽略两端点已经在同一个集合内的边,将剩余的边取出进行分类讨论
①
如果相同长度的可取的边有且仅有一条,那么这条边必取
合并这条边的两端点集合
最小生成树总长度 + i +i +i( i i i即当前枚举到的边的长度)
总种类数不变
②
如果相同长度的可取的边有两条
画图,得以下三种情况(图中每个小圆圈代表独立的集合)
对于第一种情况(左一),两条边任意取一条即可
此时最小生成树总长度 + i +i +i即可
种类数也就是 C 2 1 = 2 C_2^1=2 C21=2,让总种类数乘上 2 2 2
对于其余情况(左二、左三),在Kruskal算法中每条边都是需要取的,都会使得图中的独立集合数 − 1 -1 −1
此时最小生成树总长度 + 2 i +2i +2i
总种类数不变
③
如果相同长度的可取的边有三条
画图,得以下八种情况(蓝色数字表示涉及到的集合数量)
按涉及到的集合数量进行讨论:
- 集合数量为 2 2 2,仅一种情况(上一),此时三条边任选其一即可
- 总长度加 i i i
- 种类数乘 C 3 1 = 3 C_3^1=3 C31=3
- 集合数量为 3 3 3,有两种情况(上二、下四)
- 对于上二,重复的两条边任选其一,第三条边必选
- 总长度加 2 i 2i 2i
- 种类数乘 C 2 1 = 2 C_2^1=2 C21=2
- 对于下四,三条边任选两条便可保证图联通
- 总长度加 2 i 2i 2i
- 种类数乘 C 3 2 = 3 C_3^2=3 C32=3
- 对于上二,重复的两条边任选其一,第三条边必选
- 集合数量为 4 4 4,有三种情况(上三、下一、下二)
- 对于上三,重复的两条边任选其一,第三条边必选
- 总长度加 2 i 2i 2i
- 种类数乘 C 2 1 = 2 C_2^1=2 C21=2
- 对于下一和下二,所有边都是必选边
- 总长度加 3 i 3i 3i
- 种类数不变
- 对于上三,重复的两条边任选其一,第三条边必选
- 集合数量为 5 5 5或者 6 6 6时,所有边都是必选的
- 总长度加 3 i 3i 3i
- 种类数不变
最后,根据上述各图的特性,综合 v e c t o r / s e t vector/set vector/set等容器来判断即可
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;int n,m;
vector<P> eg[1000050];
int gp[40050];int fnd(int p)
{return p==gp[p]?p:(gp[p]=fnd(gp[p]));
}
void merge(int a,int b)
{gp[fnd(b)]=fnd(a);
}
void merge(P pd)
{merge(pd.first,pd.second);
}void kruskal()
{int tmp=1;ll mincost=0,kinds=1;rep(i,1,1000000){if(!eg[i].empty()){vector<P> vec;for(P &pd:eg[i]){int uu=fnd(pd.first),vv=fnd(pd.second);if(uu==vv)continue; //集合已经相同的话不纳入选择范围if(uu>vv)swap(uu,vv); //小在前大在后,方便判断vec.pb(P(uu,vv));}sort(vec.begin(),vec.end());if(vec.size()==1) //相同长度的(可选)边只有一条时{mincost+=i;merge(vec[0]);}else if(vec.size()==2) //相同长度的(可选)边有两条时{set<int> st; //涉及到的集合数量for(P pd:vec){st.insert(pd.first);st.insert(pd.second);}if(st.size()==2){mincost+=i;kinds=(kinds*2)%mod;merge(vec[0]);}else{mincost+=i*2;merge(vec[0]);merge(vec[1]);}}else if(vec.size()==3) //相同长度的(可选)边有三条时{set<int> st;for(P pd:vec){st.insert(pd.first);st.insert(pd.second);}if(st.size()==2){mincost+=i;kinds=(kinds*3)%mod;merge(vec[0]);}else if(st.size()==3){if(vec[0]==vec[1]||vec[1]==vec[2]) //存在两条边是相同的{if(vec[0]==vec[1]){mincost+=i*2;kinds=(kinds*2)%mod;merge(vec[0]);merge(vec[2]);}else{mincost+=i*2;kinds=(kinds*2)%mod;merge(vec[0]);merge(vec[1]);}}else{mincost+=i*2;kinds=(kinds*3)%mod;merge(vec[0]);merge(vec[1]);}}else if(st.size()==4){if(vec[0]==vec[1]||vec[1]==vec[2]){if(vec[0]==vec[1]){mincost+=i*2;kinds=(kinds*2)%mod;merge(vec[0]);merge(vec[2]);}else{mincost+=i*2;kinds=(kinds*2)%mod;merge(vec[0]);merge(vec[1]);}}else{mincost+=i*3;merge(vec[0]);merge(vec[1]);merge(vec[2]);}}else if(st.size()>=5){mincost+=i*3;merge(vec[0]);merge(vec[1]);merge(vec[2]);}}}}//mincost%=mod;cout<<mincost<<' '<<kinds<<'\n';
}void solve()
{cin>>n>>m;if(n==1){cout<<"0 1\n";return;}rep(i,1,m){int u,v,w;cin>>u>>v>>w;eg[w].pb(P(u,v));}rep(i,1,n)gp[i]=i;kruskal();
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}
G - Umbrellas for Cows
Problem Link
题意
N N N头牛分散在某一长度为 M M M的数轴上的某些点
已知买一把宽度为 i i i的雨伞需要花费 C i C_i Ci
如果要将位置为 a , b a,b a,b的两头牛用一把雨伞盖住,则雨伞的宽度至少要为 b − a + 1 b-a+1 b−a+1
问将所有牛盖住的最小花费是多少
在最优方案中,雨伞是允许重叠的
标签
Dynamic Programming
思路
明显的 O ( n 2 ) O(n^2) O(n2)的 D P DP DP
因为雨伞并不是说随着宽度 i i i增加, C i C_i Ci也一定会增加的,并且题目允许雨伞重叠
所以可以将宽度较小的雨伞与比其宽度大的雨伞中的最小花费取小,使得 C i C_i Ci最后呈一个递增的顺序
于是便可以进行 D P DP DP转移,转移方程为
d i s t a n c e = p [ i ] − p [ j + 1 ] + 1 d p [ i ] = m i n ( d p [ i ] , d p [ j ] + c [ d i s t a n c e ] ) , j < i distance=p[i]-p[j+1]+1\\ dp[i]=min(dp[i],dp[j]+c[distance]),\ j\lt i distance=p[i]−p[j+1]+1dp[i]=min(dp[i],dp[j]+c[distance]), j<i
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;int n,m;
int p[5050];
ll c[100050];
ll dp[5050];void solve()
{cin>>n>>m;rep(i,1,n)cin>>p[i];rep(i,1,m)cin>>c[i];sort(p+1,p+n+1);per(i,m-1,1)c[i]=min(c[i],c[i+1]);//rep(i,1,m) cerr<<"? "<<i<<' '<<c[i]<<'\n';dp[0]=0;rep(i,1,n){dp[i]=LINF;repp(j,0,i)dp[i]=min(dp[i],dp[j]+c[p[i]-p[j+1]+1]);}cout<<dp[n]<<'\n';
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}
H - Routing Schemes
Problem Link
防AK 😦
I - SegmentTree!
Problem Link
标签
Segment Tree
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;const int MAXN=1e5+50;ll a[MAXN];struct node
{int l,r;ll lazy,maxn;
}tree[MAXN<<2];void push_up(int id)
{tree[id].maxn=max(tree[id<<1].maxn,tree[id<<1|1].maxn);
}void push_down(int id)
{if(tree[id].lazy){int m=tree[id].r-tree[id].l+1;tree[id<<1].lazy+=tree[id].lazy;tree[id<<1|1].lazy+=tree[id].lazy;tree[id<<1].maxn+=tree[id].lazy;tree[id<<1|1].maxn+=tree[id].lazy;tree[id].lazy=0;}
}void buildTree(int id,int l,int r)
{tree[id].l=l;tree[id].r=r;tree[id].lazy=0;if(l==r){tree[id].maxn=a[l];return;}int mid=(l+r)>>1;buildTree(id<<1,l,mid);buildTree(id<<1|1,mid+1,r);push_up(id);
}void update(int id,int L,int R,ll val)
{if(L<=tree[id].l&&R>=tree[id].r){tree[id].maxn+=val;tree[id].lazy+=val;return;}push_down(id);int mid=(tree[id].r+tree[id].l)>>1;if(L<=mid)update(id<<1,L,R,val);if(R>mid)update(id<<1|1,L,R,val);push_up(id);
}ll query_max(int id,int L,int R)
{if(L<=tree[id].l&&R>=tree[id].r)return tree[id].maxn;push_down(id);int mid=(tree[id].r+tree[id].l)>>1;ll ans=-LINF;if(L<=mid)ans=max(ans,query_max(id<<1,L,R));if(R>mid)ans=max(ans,query_max(id<<1|1,L,R));return ans;
}int n,m;void solve()
{cin>>n>>m;rep(i,1,n)cin>>a[i];buildTree(1,1,n);while(m--){int op;cin>>op;if(op==1){int p; ll v;cin>>p>>v;update(1,p,p,v-a[p]);a[p]=v;}else{int l,r;cin>>l>>r;cout<<query_max(1,l,r)<<'\n';}}
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}
J - Escaping the Farm
Problem Link
题意
有 N N N个数,要求选择一些数,使得按照十进制相加时不会产生进位
问最多能选择的数的数量
标签
Brute Force
思路
由于 N N N最大只有 20 20 20,直接 O ( 2 20 ) O(2^{20}) O(220)枚举出所有状态,模拟加法判断进位即可
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;int n,a[22][11];bool check(int stat)
{rep(j,0,9){int t=0;rep(i,1,n){if(stat>>(i-1)&1)t+=a[i][j];}if(t>9)return false;}return true;
}void solve()
{cin>>n;rep(i,1,n){int d;cin>>d;int p=0;while(d){a[i][p]=d%10;d/=10;p++;}}int r=0;repp(t,1,1<<n){if(check(t))r=max(r,(int)__builtin_popcount(t));}cout<<r<<'\n';
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}
K - Counting Graphs
Problem Link
防AK 😦
https://www.cnblogs.com/stelayuri/p/15012069.html