A Sea Battle
平移过后即外围的$(w_{2} + 2) \times (h_{1} + h_{2} + 2)$的矩形周长;
1 #include<bits/stdc++.h>
2 using namespace std;
3 int main(){
4 int w1,w2,h1,h2;
5 cin>>w1>>h1>>w2>>h2;
6 int a=w1+2,b=h1+h2+2;
7 cout<<((a+b)<<1)-4<<endl;
8 return 0;
9 }
B Draw!
为了方便设初始比分为$(-1,-1)$,假设上一次的比分为$(x_{0},y_{0})$,这次比分为$(x_{1},y_{1})$
若:1.$max(x_{0} , y_{0}) > min(x_{1} , y_{1}) $ 此时变化中一定不会出现相同的情况;
2.$max(x_{0} , y_{0}) <= min(x_{1} , y_{1})$最优的情况是将$x_{0},y_{0}$都先变成较大值,再一起增加,最后再单个增加;
注意对$x==y$的一点点特判;
1 #include<bits/stdc++.h>
2 using namespace std;
3 int n,a,b,la,lb;
4 int main(){
5 scanf("%d",&n);
6 la=lb=-1;
7 long long ans=0;
8 for(int i=1;i<=n;++i){
9 scanf("%d%d",&a,&b);
10 ans+=max(min(a,b)-max(la,lb)+(la!=lb),0);
11 la=a,lb=b;
12 }
13 cout<<ans<<endl;
14 return 0;
15 }
C Birthday
做法好像还挺多,我不会证明,所以虽然过了也不知对不对,如果评论区有大佬路过的话欢迎评论;
比较麻烦的是两端怎么处理;
排序之后左半边奇数位顺序排列,然后再接偶数位的逆序排列;
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=110;
4 int n,a[N];
5 int main(){
6 scanf("%d",&n);
7 for(int i=1;i<=n;++i)scanf("%d",&a[i]);
8 sort(a+1,a+n+1);
9 for(int i=1;i<=n;i+=2)printf("%d ",a[i]);
10 if(n&1)n--;for(int i=n;i;i-=2)printf("%d ",a[i]);
11 return 0;
12 }
D Gourmet choice
相当于只有'>','=',对等于符号用并查集缩点;
对x>y建边:x->y;
对于得到DAG,记录一个点出发的最长链,即为答案;
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=2010;
4 int n,m,f[N],mx[N],o=1,hd[N],vis[N];
5 char s[N][N];
6 struct Edge{int v,nt;}E[N*N];
7 void adde(int u,int v){E[o]=(Edge){v,hd[u]};hd[u]=o++;}
8 bool dfs(int u){
9 mx[u]=vis[u]=1;
10 for(int i=hd[u];i;i=E[i].nt){
11 int v=E[i].v;
12 if(vis[v]==1)return false;
13 if(!vis[v]){if(!dfs(v))return false;}
14 mx[u]=max(mx[u],mx[v]+1);
15 }
16 vis[u]=2;
17 return true;
18 }
19 int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
20 int main(){
21 #ifndef ONLINE_JUDGE
22 freopen("D.in","r",stdin);
23 freopen("D.out","w",stdout);
24 #endif
25 scanf("%d%d",&n,&m);
26 for(int i=1;i<=n+m;++i)f[i]=i;
27 for(int i=1;i<=n;++i)scanf("%s",s[i]+1);
28 for(int i=1;i<=n;++i)
29 for(int j=1;j<=m;++j)if(s[i][j]=='=')f[find(i)]=find(j+n);
30 for(int i=1;i<=n;++i)
31 for(int j=1;j<=m;++j)
32 if(s[i][j]=='>')adde(find(i),find(j+n));
33 else if(s[i][j]=='<')adde(find(j+n),find(i));
34 for(int i=1;i<=n+m;++i)if(find(i)==i&&!vis[i]){
35 if(!dfs(i)){puts("NO");return 0;}
36 }
37 puts("YES");
38 for(int i=1;i<=n;++i)printf("%d ",mx[find(i)]);
39 printf("\n");
40 for(int i=1;i<=m;++i)printf("%d ",mx[find(i+n)]);
41 printf("\n");
42 return 0;
43 }
E String Multiplication
考虑每一个字符,分情况模拟即可:
对于$a+b$,
如果$b$是一个全为$x$的串,仅会连接原来的字符$x$,其余置1;
如果$b$是一个首末连续段不相接但是都为$x$的段,修改$x$,其余置1;
如果$b$是一个首末连续段不相接为$x,y(x!=y)$的段,修改$x,y$,其余置1;
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=100010;
4 int n,len,a[26],b[26],lt,p1,p2;
5 char s[N];
6 inline void upd(int&x,int y){if(x<y)x=y;}
7 void cal(){
8 len=strlen(s+1);
9 p1=1;while(p1<len&&s[1]==s[p1+1])p1++;
10 p2=1;while(p2<len&&s[len]==s[len-p2])p2++;
11 for(int i=1,cnt=1;i<len;++i)if(s[i]!=s[i+1]){
12 upd(a[s[i]-'a'], cnt);
13 cnt=1;
14 }else cnt++;
15 upd(a[s[len]-'a'], p2);
16 }
17 int main(){
18 #ifndef ONLINE_JUDGE
19 freopen("E.in","r",stdin);
20 freopen("E.out","w",stdout);
21 #endif
22 scanf("%d",&n);
23 scanf("%s",s+1);cal();
24 for(int i=0;i<26;++i)b[i]=a[i],a[i]=0;
25 for(int i=1;i<n;++i){
26 scanf("%s",s+1);cal();
27 if(p1==len){
28 int x=s[1]-'a';
29 b[x]=a[x]*b[x]+a[x]+b[x];
30 for(int j=0;j<26;++j)if(j!=x)b[j]=b[j]?1:0;
31 }else if(s[1]==s[len]){
32 int x=s[1]-'a';
33 if(b[x])b[x]=p1+p2+1;
34 for(int j=0;j<26;++j)if(j!=x)b[j]=b[j]?1:0;
35 }else{
36 int x=s[1]-'a',y=s[len]-'a';
37 if(b[x])b[x]=p1+1;
38 if(b[y])b[y]=p2+1;
39 for(int j=0;j<26;++j)if(j!=x&&j!=y)b[j]=b[j]?1:0;
40 }
41 for(int j=0;j<26;++j)upd(b[j],a[j]),a[j]=0;
42 }
43 int ans=0;
44 for(int i=0;i<26;++i)upd(ans, b[i]);
45 cout<<ans<<endl;
46 return 0;
47 }
F Asya And Kittens
用并查集模拟,同时维护两边的位置即可
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=150100;
4 int n,d[N],pre[N],nxt[N],f[N];
5 vector<int>g[N];
6 void adde(int u,int v){
7 g[u].push_back(v);
8 g[v].push_back(u);
9 d[u]++;
10 d[v]++;
11 }
12 void dfs(int u,int fa){
13 printf("%d ",u);
14 for(int i=0;i<(int)g[u].size();++i){
15 if(g[u][i]!=fa)dfs(g[u][i],u);
16 }
17 }
18 int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
19 int main(){
20 scanf("%d",&n);
21 for(int i=1;i<=n;++i)pre[i]=nxt[i]=f[i]=i;
22 for(int i=1;i<n;++i){
23 int x,y;
24 scanf("%d%d",&x,&y);
25 x=find(x),y=find(y);
26 adde(nxt[x],pre[y]);
27 nxt[x]=nxt[y];
28 f[y]=x;
29 }
30 int rt=0;
31 for(int i=1;i<=n;++i)if(d[i]==1){rt=i;break;}
32 dfs(rt,0);
33 return 0;
34 }
G Most Dangerous Shark
这题倒还不错;
先考虑如果只有向左倒怎么办;
一个骨牌向左可以压倒的一定是一段区间,
由于连续效应,$n$张骨牌可以形成若干段区间,这些区间互不相交,只要贪心选右端点即可;
处理所有向左的范围只需要依次加入,用一个栈维护所有右端点,每次加入弹出并合并末尾的若干当前点$i$可到的右端点;
同理可以预处理向右的范围;
回到原题,$dp[i]$表示前$i$个的答案;
考虑转移$(j<i)$,一个是$i$向左推倒$j$转移,一个是$j$向右倒到$i$转移;
第一种直接从$i$可推倒的最远$j$转移即可;
第二种,当$j1<j2$并且$j1$可以推倒$j2$,同时$dp[j1-1]+c_{j1}<dp[j2-1]+c_{j2}$,$j2$显然不会更优:
所以可以用一个栈维护$dp[i-1]+c_{i}$的降序即可;
1 #include<bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4 const int N=250010,M=10000010;
5 int n,m,q,ta[M],tb[M],a[M],len[N],l[M],r[M],st[M],tp;
6 ll b[M],dp[M];
7 char gc(){
8 static char*p1,*p2,s[1000000];
9 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
10 return(p1==p2)?EOF:*p1++;
11 }
12 int rd(){
13 int x=0;char c=gc();
14 while(c<'0'||c>'9')c=gc();
15 while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
16 return x;
17 }
18 int main(){
19 //freopen("G.in","r",stdin);
20 //freopen("G.out","w",stdout);
21 n=rd();m=rd();
22 for(int i=1,now;i<=n;++i){
23 len[i]=rd();
24 now=len[i-1];for(int j=1;j<=len[i];++j)ta[++now]=rd();
25 now=len[i-1];for(int j=1;j<=len[i];++j)tb[++now]=rd();
26 len[i]+=len[i-1];
27 }
28 q=rd();
29 for(int i=1,now=0;i<=q;++i){
30 int id=rd(),mul=rd(),tmp=now;
31 for(int j=len[id-1]+1;j<=len[id];++j)a[++tmp]=ta[j];
32 for(int j=len[id-1]+1;j<=len[id];++j)b[++now]=1ll*tb[j]*mul;
33 }
34 for(int i=1;i<=m;++i){
35 l[i]=max(1,i-a[i]+1);
36 while(tp&&st[tp]>=l[i])l[i]=min(l[i],l[st[tp--]]);
37 st[++tp]=i;
38 }tp=0;
39 for(int i=m;i>=1;--i){
40 r[i]=min(m,i+a[i]-1);
41 while(tp&&st[tp]<=r[i])r[i]=max(r[i],r[st[tp--]]);
42 st[++tp]=i;
43 }tp=0;
44 for(int i=1;i<=m;++i){
45 dp[i]=dp[l[i]-1]+b[i];
46 while(tp&&r[st[tp]]<i)tp--;
47 if(tp)dp[i]=min(dp[i],dp[st[tp]-1]+b[st[tp]]);
48 if(!tp||dp[i-1]+b[i]<dp[st[tp]-1]+b[st[tp]])st[++tp]=i;
49 }
50 cout<<dp[m]<<endl;
51 return 0;
52 }
来源:oschina
链接:https://my.oschina.net/u/4351540/blog/3638475