XX Open Cup, GP of Siberia 训练记录
A.
设坐标为\((i,j)\)
考虑从任意一个点出发,每走一步\((i+j)\)的奇偶性就会发生变化,那么我们最后的局面就是\(2\)在奇数格\(1\)在偶数格或者\(2\)在偶数格\(1\)在奇数格
取较小即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m; 4 char s[1005][1005]; 5 int main() 6 { 7 scanf("%d%d",&n,&m); 8 for(int i=1;i<=n;++i)scanf("%s",s[i]+1); 9 int ans1=0,ans2=0; 10 for(int i=1;i<=n;++i) 11 for(int j=1;j<=m;++j) 12 { 13 if((i+j)&1) 14 { 15 if(s[i][j]=='1')ans1++; 16 else ans2++; 17 } 18 else 19 { 20 if(s[i][j]=='2')ans1++; 21 else ans2++; 22 } 23 } 24 printf("%d\n",min(ans1,ans2)); 25 }
E.
签到题
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define maxn 1005 4 using namespace std; 5 int n; 6 ll a[maxn]; 7 int main() 8 { 9 scanf("%d",&n); 10 for(int i=1;i<=n;++i)scanf("%lld",&a[i]); 11 for(int i=2;i<=n;++i) 12 { 13 if(a[i]<=a[i-1]) 14 { 15 ll k=a[i-1]/a[i]; 16 a[i]+=k*a[i]; 17 } 18 } 19 for(int i=1;i<=n;++i)printf("%lld ",a[i]); 20 }
F.
先用dp处理出每种票内部最好的安排,得到每种票的最大收益作为价值,再对所有票做一个完全背包
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=110,M=1e6+10; 4 int n,K,s,num[3][N],cost[N*4],tot; 5 double dp[N][N][N],prz[N*4],r[3][N],f[M]; 6 long long p; 7 void init(){ 8 for(int w=1;w<=K;w++){ 9 dp[0][0][0]=1.0; 10 for(int i=1;i<=n;i++){ 11 double one=max(r[0][i],max(r[1][i],r[2][i])); 12 double two=max(r[0][i]+r[1][i],max(r[2][i]+r[1][i],r[0][i]+r[2][i])); 13 for(int j=0;j<=num[0][w];j++) 14 for(int k=0;k<=num[1][w];k++){ 15 int l=i-j-k; 16 if(l<0)break; 17 if(j)dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k]*two); 18 if(k)dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k-1]); 19 if(l)dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]*one); 20 } 21 22 } 23 prz[w]=dp[n][num[0][w]][num[1][w]]; 24 } 25 } 26 int main(){ 27 cin>>n>>K>>s>>p; 28 for(int i=1;i<=n;i++) 29 cin>>r[0][i]>>r[1][i]>>r[2][i]; 30 for(int i=1;i<=K;i++) 31 scanf("%d%d%d",&num[0][i],&num[1][i],&cost[i]); 32 init(); 33 for(int i=1;i<=K;i++) 34 for(int j=cost[i];j<=s;j++){ 35 f[j]=max(f[j],f[j-cost[i]]+prz[i]); 36 } 37 double ans=0; 38 for(int i=0;i<=s;i++)ans=max(ans,f[i]); 39 printf("%.12lf",ans*p); 40 }
G.
考虑每层独立,因此我们只要考虑一层的情况就行了
我们每次砸掉\(k\)格,然后跳过后面一段空的,再找后面一个有东西的再砸就行了
这个我们可以预处理下一次砸在哪,发现这东西可以倍增,那么预处理一下倍增数组就行了
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,k,q; 4 char a[13][100005]; 5 int L[13][100005],R[13][100005]; 6 int nxt[13][100005][21]; 7 int main() 8 { 9 scanf("%d%d%d%d",&n,&m,&k,&q); 10 for(int i=1;i<=n;++i)scanf("%s",a[i]+1); 11 for(int i=1;i<=n;++i) 12 { 13 L[i][0]=0; 14 for(int j=1;j<=m;++j) 15 { 16 if(a[i][j]=='X')L[i][j]=j; 17 else L[i][j]=L[i][j-1]; 18 } 19 R[i][m+1]=m+1; 20 for(int j=m;j>=1;--j) 21 { 22 if(a[i][j]=='X')R[i][j]=j; 23 else R[i][j]=R[i][j+1]; 24 } 25 } 26 for(int i=1;i<=n;++i) 27 for(int j=1;j<=m+1;++j) 28 nxt[i][j][0]=min(m+1,R[i][j]+k); 29 for(int i=1;i<=n;++i) 30 for(int p=1;p<=19;++p) 31 for(int j=1;j<=m+1;++j) 32 nxt[i][j][p]=nxt[i][nxt[i][j][p-1]][p-1]; 33 while(q--) 34 { 35 int d,l,r; 36 scanf("%d%d%d",&d,&l,&r); 37 int ans=0; 38 for(int i=1;i<=d;++i) 39 { 40 int st=l,en=L[i][r]; 41 if(st>en)continue; 42 int t=0; 43 for(int j=18;j>=0;--j)if(nxt[i][st][j]<=en) 44 { 45 st=nxt[i][st][j]; 46 t+=(1<<j); 47 } 48 t++; 49 ans+=t; 50 } 51 printf("%d\n",ans); 52 } 53 }
H.
考虑找第\(2\)小的数字,大概可以接受的比较次数是\(n+logn\)次
我们利用线段树结构进行比较,利用\(n\)次求出最小值
那么我们沿着最小值那条链走下去,这条链不选每步取剩下子树较大的就可以得到次小值
1 #include<bits/stdc++.h> 2 #define maxn 100005 3 using namespace std; 4 int n; 5 int mnid[maxn*4]; 6 bool query(int x,int y) 7 { 8 printf("? %d %d\n",x-1,y-1); 9 fflush(stdout); 10 char op[3]; 11 scanf("%s",op); 12 if(op[0]=='<')return 0; 13 else return 1; 14 } 15 void build(int rt,int l,int r) 16 { 17 if(l==r) 18 { 19 mnid[rt]=l; 20 return; 21 } 22 int mid=(l+r)>>1; 23 build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); 24 if(!query(mnid[rt<<1],mnid[rt<<1|1]))mnid[rt]=mnid[rt<<1]; 25 else mnid[rt]=mnid[rt<<1|1]; 26 } 27 int ans; 28 void solve(int rt,int l,int r) 29 { 30 int mid=(l+r)>>1; 31 if(l==r)return; 32 if(mnid[rt]==mnid[rt<<1]) 33 { 34 if(rt==1)ans=mnid[rt<<1|1]; 35 else if(query(ans,mnid[rt<<1|1]))ans=mnid[rt<<1|1]; 36 solve(rt<<1,l,mid); 37 } 38 else 39 { 40 if(rt==1)ans=mnid[rt<<1]; 41 else if(query(ans,mnid[rt<<1]))ans=mnid[rt<<1]; 42 solve(rt<<1|1,mid+1,r); 43 } 44 } 45 int main() 46 { 47 scanf("%d",&n); 48 build(1,1,n); 49 solve(1,1,n); 50 printf("! %d\n",ans-1); 51 fflush(stdout); 52 }
K.
换根树DP,叶子节点需要特殊处理(\(K_2\)是特例)
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int n; 5 vector< pair<int,ll> > g[3000005]; 6 int d[3000005]; 7 ll fw[3000005]; 8 ll dp[3000005],Ans[3000005]; 9 void dfs(int u,int f) 10 { 11 for(auto p:g[u])if(p.first==f)fw[u]=p.second; 12 for(auto p:g[u])if(p.first!=f) 13 { 14 int v=p.first; 15 dfs(v,u); 16 dp[u]+=min(fw[v],dp[v]); 17 } 18 if(d[u]==1)dp[u]=fw[u]; 19 } 20 void dfs2(int u,int f) 21 { 22 for(auto p:g[u])if(p.first!=f) 23 { 24 int v=p.first; 25 ll w=p.second; 26 Ans[v]=min(w,Ans[u]-min(dp[v],fw[v])); 27 if(d[v]>1)Ans[v]+=dp[v]; 28 dfs2(v,u); 29 } 30 } 31 int main() 32 { 33 scanf("%d",&n); 34 for(int i=1;i<n;++i) 35 { 36 int u,v,x,y; 37 scanf("%d%d%lld%lld",&u,&v,&x,&y); 38 g[u].push_back(make_pair(v,x)); 39 g[v].push_back(make_pair(u,y)); 40 d[u]++;d[v]++; 41 } 42 if(n==2) 43 { 44 printf("%d\n%d\n",g[2][0].second,g[1][0].second); 45 return 0; 46 } 47 int rt=0; 48 for(int i=1;i<=n;++i)if(d[i]>1){rt=i;break;} 49 dfs(rt,0); 50 Ans[rt]=dp[rt]; 51 dfs2(rt,0); 52 for(int i=1;i<=n;++i)printf("%lld\n",Ans[i]); 53 }

浙公网安备 33010602011771号