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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

posted @ 2020-04-02 17:15  uuzhatetree  阅读(258)  评论(0)    收藏  举报