C. From S To T
题意:
给你三个字符串s,p,t,问你能否在s串中的任何位置加入p串中的任何字符,从而使s串变成t串?
题解:模拟题
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<functional>
#include<set>
#include<map>
#include<iterator>
#include<queue>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
#define mp make_pair
const int N=1e7+10;
const long long INF=1e18;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m,x,y,t;
int a[30],b[30];
string str1,str2,str3 ;
bool contains(string t, string s) {//判断s是否为t的子串
int i = 0;
for (char c : s) {
if (i == t.size()) return false;
while (i < t.size() && c != t[i]) {
i++;
}
i++;
}
return i <= t.size();
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
vector<int>q[30],p[30];
cin>>str1>>str2>>str3;
for(int i=0;i<str1.size();i++)
{
q[str1[i]-'a'].push_back(i);
a[str1[i]-'a']++;
}
for(int i=0;i<str2.size();i++)
{
p[str2[i]-'a'].push_back(i);
b[str2[i]-'a']++;
}
for(int i=0;i<str3.size();i++)
{
a[str3[i]-'a']++;
}
int flag=0;
flag=!contains(str2, str1);
if(flag==1)
cout<<"NO"<<endl;
else
{
for(int i=0;i<26;i++)
{
if(a[i]<b[i])
{
flag=1;break;
}
}
if(flag==1) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
}
}
B. Yet Another Crosses Problem
题意:找补充次数最少的十字架
题解:模拟
注意:
1.空间开太大memset超时
2.main函数内建立数组,变量作范围(没这么写过…),用memset清空一下
结构体写着写着就忘记干啥的了…自闭ing
版本一: 1279 ms,
用sort找到最大值反而慢,跟数据有关吧,没有排序的必要,反而拖时长
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<functional>
#include<set>
#include<map>
#include<iterator>
#include<queue>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
#define mp make_pair
const int N=5e4+10;
const long long INF=1e18;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m,x,y,t;
struct note
{
int x,id;
}a[N],b[N];
bool cmp(note a,note b)
{
return a.x<b.x;
}
string str;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
cin>>n>>m;
int vis[n][m];
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
cin>>str;
for(int j=0;j<m;j++)
{
if(str[j]=='*')
a[j].x++,a[j].id=j,b[i].x++,b[i].id=i;
if(str[j]=='.')
vis[i][j]=1;
}
}
sort(a,a+m,cmp);
sort(b,b+n,cmp);
int flag=0;
for(int i=n-1;i>=0;i--)
{
if(b[i].x==b[n-1].x)
{
for(int j=m-1;j>=0;j--)
{
if(a[j].x==a[m-1].x)
{
if(vis[b[i].id][a[j].id]==1)
{
flag=1;
//cout<<i<<" "<<j;
break;
}
}
else
break;
}
}
else break;
}
if(flag==0)
cout<<n+m-(a[m-1].x+b[n-1].x)<<endl;
else
cout<<n+m-(a[m-1].x+b[n-1].x)-1<<endl;
}
}
版本二:545 ms
反而暴力快一倍…
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<functional>
#include<set>
#include<map>
#include<iterator>
#include<queue>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
#define mp make_pair
const int N=5e4+10;
const long long INF=1e18;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m,x,y,t;
int a[N],b[N];
char str[N];
int main()
{
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
scanf("%d",&t);
while(t--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
scanf("%d%d",&n,&m);
int vis[n][m];
memset(vis,0,sizeof(vis));//��ʼ��
for(int i=0;i<n;i++)
{
scanf("%s",str);
for(int j=0;j<m;j++)
{
if(str[j]=='*')
a[j]++,b[i]++;
if(str[j]=='.')
vis[i][j]=1;
}
}
int flag=0,ans=N;
for(int i=0;i<n;i++)
{
for(int j=0;j<=m;j++)
{
flag=0;
if(vis[i][j]==1)
{
flag=1;
}
if(flag==0)
ans=min(n+m-(a[j]+b[i]),ans);
else
ans=min(n+m-(a[j]+b[i])-1,ans);
if(ans==0)
break;
}
if(ans==0)
break;
}
printf("%d\n",ans);
}
}
1-2-K Game
题解:
Let’s determine for each cell whether it’s winning or losing position (we can do it since the game is symmetric and doesn’t depend on a player). The 0-th cell is obviously losing, the 1-st and 2-nd ones is both winning, since we can move to the 0-th cell and put our opponent in the losing position (here comes criterion: the position is winning if and only if there is a move to the losing position).
If k is large enough, then the 0-th, 3-rd, 6-th, 9-th… are losing. So here comes divisibility by 3. If then this move doesn’t change anything, since if then so it’s not the move to the losing position, so x doesn’t become the winning one.
Otherwise, if then the k-th positions becomes winning, but the (k + 1)-th cell is losing (all moves are to (k - 1)-th, k-th or 1-st cells and all of them are winning). The (k + 2)-th and (k + 3)-th cells are winning and so on. In the end, we came up with cycle of length k + 1 where position divisible by 3 except k are losing.
All we need to do is small case work.
博弈题,想不明白的话,就找规律(不用想明白了,就直接找规律吧,列举一些情况然后观察就好了,想原理脑袋疼…
1.当
k
k
k%
3
!
=
0
3!=0
3!=0 的时候很好理解,和巴什博弈差不多
这时候不会有一个原来的必败态因为走k步而到达另一个必败态,也就是说这时候k对胜负是没有影响的,可以直接认为k不存在,输赢和上面一样。
2.主要是
k
k
k%
3
=
0
3=0
3=0的时候,怎么考虑
__ 先列举一下前
k
+
1
k+1
k+1个元素:(
k
=
6
k=6
k=6,
T
T
T表示赢)
0_1_2_3_4_5_6_7
0_T_T_0_T_T_T_0
上图的依据:
如果
m
m
m点是必败点,那么
m
+
1
,
m
+
2
,
m
+
k
m+1,m+2,m+k
m+1,m+2,m+k就是必胜点,因为如果在这个点上面,我们可以通过走
1
,
2
,
k
1,2,k
1,2,k步走到一个必败点,从而赢得胜利。
如果一个点m为必败点那么,这个点
m
−
1
,
m
−
2
,
m
−
k
m-1,m-2,m-k
m−1,m−2,m−k一定为必胜点,因为这个点只能由后手走到。
所以总结一下就是:能被先手走到的点是
T
T
T,仅能被后手走到的点是
0
0
0
猜想:从必败点仅通过一步,如何都走不到的第一个点一定为必败点。
所以胜利的条件就是开始的时候是位于胜利的格子上。然后推理可得结论,如果思考不出原理,也可以像上图一样枚举状态,最后发现有一个 k + 1 k+1 k+1为周期的循环。
#include <bits/stdc++.h>
using namespace std;
int n, k;
inline bool read() {
if(!(cin >> n >> k))
return false;
return true;
}
void solve() {
bool win = true;
if(k % 3 == 0) {
int np = n % (k + 1);
if(np % 3 == 0 && np != k)
win = false;
} else {
int np = n % 3;
if(np == 0)
win = false;
}
puts(win ? "Alice" : "Bob");
}
int main(){
int T; cin >> T;
while(T--) {
read();
solve();
}
return 0;
}
Codeforces Round #278 B - Strip
题意:给一个数组,然后要求把这个数组分成几段,每一段最值差不超过S,每一段的区间长度不少于L,问最少能够分成多少段?
题解:(dp+单调队列+ST表)
We can use dynamic programming to solve this problem.
Let f[i] denote the minimal number of pieces that the first i numbers can be split into. g[i] denote the maximal length of substrip whose right border is i(included) and it satisfy the condition.
Then f[i] = min(f[k]) + 1, where i - g[i] ≤ k ≤ i - l.
We can use monotonic queue to calculate g[i] and f[i]. And this can be implemented in O(n)
We can also use sparse table or segment tree to solve the problem, the time complexity is or (It should be well-implemented).
注意:INF ——0x3f3f3f3f
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<functional>
#include<set>
#include<map>
#include<stack>
#include<iterator>
#include<queue>
#include<vector>
#include<string>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+7;
struct note
{
int x,id;
}q[maxn];
int st[maxn][20],st1[maxn][20],a[maxn],n,dp[maxn];
int head,tail;
void init(int n)
{
for(int i=1;i<=n;i++) st1[i][0]=st[i][0]=a[i];//初始化,从i点开始2^j长度的极值
for(int j=1;j<20;j++)
for(int i=1;i<=n;i++)
if(i+(1<<(j-1))<=n)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]),
st1[i][j]=max(st1[i][j-1],st1[i+(1<<(j-1))][j-1]); //最值
}
int query(int l,int r)
{
int len=log2(r-l+1);
return max(st1[l][len],st1[r-(1<<len)+1][len])-min(st[l][len],st[r-(1<<len)+1][len]);
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int s,len; cin>>n>>s>>len;
for(int i=1;i<=n;i++) cin>>a[i];
init(n);
int l,r,ans;
if(len>n||query(1,len)>s) return cout<<-1<<endl,0;
memset(dp,INF,sizeof(dp)); dp[0]=0; q[tail].id=0,q[tail].x=0,tail++;
dp[len]=1;
for(int i=len+1;i<=n;i++)
{
l=1,r=i-len+1,ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(query(mid,i)<=s) r=mid-1,ans=mid;
else l=mid+1;
}
//单调队列维护到i为止的划分的最小块的个数
while(head<tail&&q[tail-1].x>=dp[i-len]) tail--; ///
q[tail].x=dp[i-len],q[tail].id=i-len,tail++; ///
if(ans!=-1)
{
while(head<tail&&q[head].id<ans-1) head++; ///
if(head<tail) ///
dp[i]=min(dp[i],q[head].x+1);//动态转移方程
}
}
if(dp[n]==INF) dp[n]=-1;
cout<<dp[n]<<endl;
}
G - Check Corners
二维ST表的模板题
#include<iostream>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int dp[301][301][9][9];
int a[301][301];
void init(int n,int m)
{
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
dp[i][j][0][0]=a[i][j];
int t1=log(n)/log(2)+1,t2=log(m)/log(2)+1;
for(int l=0;l<t1;++l)
for(int k=0;k<t2;++k)
if(l+k)
for(int i=1;i<=n-(1<<l)+1;++i)
for(int j=1;j<=m-(1<<k)+1;++j)
if(l==0)
dp[i][j][l][k]=max(dp[i][j][l][k-1],dp[i][j+(1<<(k-1))-1+1][l][k-1]);
else
dp[i][j][l][k]=max(dp[i][j][l-1][k],dp[i+(1<<(l-1))-1+1][j][l-1][k]);
}
int query(int x,int y,int z,int v)
{
int t1=log(z-x+1)/log(2),t2=log(v-y+1)/log(2);
int ans=max(dp[x][y][t1][t2],dp[z-(1<<t1)+1][v-(1<<t2)+1][t1][t2]);
ans=max(dp[x][v-(1<<t2)+1][t1][t2],ans);
ans=max(ans,dp[z-(1<<t1)+1][y][t1][t2]);
return ans;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,m,q;
while(cin>>n>>m)
{
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
cin>>a[i][j];
init(n,m);
cin>>q;
while(q--)
{
int x,y,z,v;
cin>>x>>y>>z>>v;
int ans=query(x,y,z,v);
cout<<ans<<" ";
if(a[x][y]==ans||a[z][v]==ans||a[x][v]==ans||a[z][y]==ans)cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
}
return 0;
}