2021-2-24对内个人赛
A题 CodeForces - 1303A
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
char s[105];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s+1);
int ans=0,pre=0,len=strlen(s+1);
for(int i=1;i<=len;i++)
{
if(s[i]=='0')
continue;
if(pre)
ans+=i-pre-1;
pre=i;
}
printf("%d\n",ans);
}
return 0;
}
B CodeForces - 1300A
首先我们考虑数列中出现的0,只要有0存在,那么数列中所有数字的积必定为0,所以我们先把数列中的所有0变成1.在进行这样的操作后,我们再检查一下这个时候数列中所有数字的和是否为0,如果为0 的话再加一次1就可以了(和为0的话,必定又有负数又有整数,随便选一个正数+1就能避免0的再次出现)
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
IOS;
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int sum=0,res=0;
while(n--){
int x;
cin>>x;
if(x==0){
x++;
res++;
}
sum+=x;
}
if(sum==0)
res++;
cout<<res<<endl;
}
return 0;
}
C CodeForces - 40A
看各位的代码有点麻烦,看看我这优雅的代码吧
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
int x,y,l,r;
int main(){
scanf("%d%d",&x,&y);
l=x*x+y*y;
for(r=1;r*r<l;r++);
puts(r*r==l||(r&1)^(x*y<0)?"black":"white");
return 0;
}
D CodeForces - 46B
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
string M[5]= {"S","M","L","XL","XXL"};
int main()
{
IOS;
int k,n[5];
for(int i=0;i<5;i++)
cin>>n[i];
cin>>k;
for(int i=0;i<k;i++)
{
string s;
cin>>s;
int j;
for(j=0;s!=M[j];j++);
int b=-1000;
for(int k=0;k<5;k++)
{
if(!n[k])
continue;
if(abs(k-j)<=abs(b-j))
b=k;
}
cout <<M[b]<<endl;
n[b]--;
}
return 0;
}
E CodeForces - 48B
一眼看会有点不知所措,再仔细一看其实就是求一个矩阵前缀和,然后行列各扫一遍,求差的最小值嘛。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int s[55][55],maxn=9999999;
int main()
{
IOS;
int n,m,r,c,i,j;
cin>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
cin>>s[i][j];
s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+s[i][j];
}
cin>>r>>c;
for(i=r;i<=n;i++)
for(j=c;j<=m;j++)
maxn=min(maxn,s[i][j]-s[i-r][j]-s[i][j-c]+s[i-r][j-c]);
swap(r,c);
for(i=r;i<=n;i++)
for(j=c;j<=m;j++)
maxn=min(maxn,s[i][j]-s[i-r][j]-s[i][j-c]+s[i-r][j-c]);
cout<<maxn;
}
F CodeForces - 1293B
简单结论题
首先我们要知道,总共是n个人,不管我们怎么选择方案,所有的分数(未约分过)的分子部分累加起来都是n。在分子总数固定的情况下,我们需要让每个分子对应的分母尽可能小,这样才能使得值更大。
假设我们在n个人中去掉两个人,有两种方案,一种是2/n也就是1/n+1/n,另一种是1/n+1/(n-1),明显后面的那个更大。可以由此推出一个结论,最优方案就是每次只让一个人出局。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
typedef long long ll;
int main()
{
IOS;
ll n;
cin>>n;
double ans=0;
for(ll i=1;i<=n;i++)
{
ans+=(double)1/i;
}
cout<<ans<<endl;
}
G CodeForces - 1304B
这道题我也卡了很久疯狂wa,细节坑我。
由于所有的字符串长度都是相等的,因此最后的字符串必然可以切割成长度为m的部分,并且对称的部分只能是两个原本的字符串,或者是最为最终回文串的中间部分的那个字符串,它需要满足自己就是个回文串。
直接暴力匹配是否有对称的字符串就行了,注意中间还可以放一个自身就是回文串的字符串。`
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f //1061109567
#define llINF 9223372036854775807
#define ll long long
const ll maxn=1e2+7;
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
bool flag[maxn];
string s[maxn];
int main()
{
IOS;
ll n,m;
cin>>n>>m;
for(ll i=1;i<=n;i++) cin>>s[i];
string ans,mid,right;//ans暂存左侧部分,mid保存中间可能存在的对称部分,right保存右侧部分,也就是ans的镜像
for(ll i=1;i<=n;i++)
{
bool F=0; //F记录是否存在字符串与当前字符串镜像
for(ll j=i+1;j<=n;j++)
{
if(!flag[j]) //如果该字符串仍然未被使用
{
bool f=1; //记录s[i]和s[j]是否为对称的字符串
for(ll k=0;k<m;k++)
if(s[i][k]!=s[j][m-k-1]) f=0;
if(f) //如果满足
{
flag[j]=1; //使用字符串j
right=s[j]+right; //将字符串j加到right部分去
F=1; //记录找到s[i]的对称字符串,跳出循环
break;
}
}
}
if(F) ans+=s[i]; //如果找到了对称的字符串,那就把s[i]加到左侧的ans去
else //如果没找到的话那就检测s[i]自身是不是一个回文串,如果是就放到mid部分去。
{
F=1;
for(ll j=0;j<m;j++)
if(s[i][j]!=s[i][m-j-1]) F=0;
if(F) mid=s[i];
}
}
ans+=mid+right; //拼接ans+mid+right
cout<<ans.size()<<endl;
cout<<ans<<endl;
}
H CodeForces 75C
给出 a , b 问你在区间 [ l . r ] 中的最大公因子是多少,区间内的最大大公因子肯定是 g c d ( a , b ) 的因子,所以先把最大公因子的所有因子都预处理出来,在区间内二分查找就行了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll c[100010];
ll gcd(ll a,ll b)
{
return b ? gcd(b,a%b) : a;
}
int main()
{
ll a,b,n,d,k=0;
scanf("%lld%lld%lld",&a,&b,&n);
d=gcd(a,b);
for(int i=1;i*i<=d;i++)
{
if(d%i==0)
{
c[k++]=i;
if(i*i!=d)c[k++]=d/i;
}
}
sort(c,c+k);
while(n--)
{
ll l,h;
scanf("%lld%lld",&l,&h);
if(l>d)//区间始终比最大公约数大
{
printf("-1\n");
continue;
}
ll ans;
ans=upper_bound(c,c+k,h)-c-1;
if(ans==-1||c[ans]<l)//没找到或c[ans]<l并且c[ans+1]>h
{
printf("-1\n");
continue;
}
printf("%lld\n",c[ans]);
}
}
I CodeForces - 1293C
本题也还是个思维题,题面迷惑性比较大
对于每一个格子,我们考虑的是它的通或者不通,与哪些格子组合起来会对结果产生影响。
如果要走过的地图上有一块陷阱(x, y), 并且陷阱所在的另一行上的(x, y+1)或(x, y)或(x, y-1)三块中的任何一块内也有陷阱, 则一定是无法达到终点的. 所以不妨每当出现一种无法通过的情况, 我们就记录一次, 如果没有不可通过的情况则就可以通过.
#include<bits/stdc++.h>
using namespace std;
const int maxx=1e5+100;
int vis[3][maxx];
int n,q;
int main()
{
scanf("%d%d",&n,&q);
int x,y;
int ans=0;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
if(vis[x][y]==0)
{
vis[x][y]=1;
if(vis[3-x][y]) ans++;
if(vis[3-x][y+1]&&y+1<=n) ans++;
if(vis[3-x][y-1]&&y-1>=1) ans++;
}
else
{
vis[x][y]=0;
if(vis[3-x][y]) ans--;
if(vis[3-x][y+1]&&y+1<=n) ans--;
if(vis[3-x][y-1]&&y-1>=1) ans--;
}
if(!ans) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
J CodeForces - 1295C
贪心,dp优化字符串匹配
暴力匹配是超时的,用dp数组来记录每个位置后每个字符对应位置下标,O(1)查询下一个匹配字符的位置就好了。
#include<bits/stdc++.h>
#define INF 0x7f7f7f7f //2139062143
#define INF1 0x3f3f3f3f //1061109567
#define INF2 2147483647
#define llINF 9223372036854775807
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
char a[100010],b[100010];
int dp[100010][26],Flag[26];//dp[i][j]记录在第i个下标开始往后找,第一个字符('a'+j)所在的位置的下一个位置(也就是接下去开始匹配的第一个位置),如果等于INF2则代表已经不存在字符('a'+j)
//Flag[i]记录字符('a'+j)是否在字符串a中出现,用于检测能否构建字符串b,如果字符串b需要的某个字符在字符串a中不存在,那么必然无法构建。
void clr()
{
for(int i=0;i<100010;i++)
for(int j=0;j<26;j++)
dp[i][j]=INF2;
for(int i=0;i<26;i++)
Flag[i]=0;
}
int main()
{
IOS;
int T;
cin>>T;
cin.get();
while(T--)
{
cin.getline(a,100010);
cin.getline(b,100010);
clr();
int lens=strlen(a),lent=strlen(b);
for(int i=lens-1;i>=0;i--) //从后往前更新dp数组
{
int x=a[i]-'a';
Flag[x]=1;
for(int j=0;j<26;j++) //直接复制i+1位置以后的26个字母出现的第一个下标位置
dp[i][j]=dp[i+1][j];
dp[i][x]=i+1; //更新当前位置的字母,位置置为当前位置的后一个//我们匹配i位置后的字符('a'+x)后,待匹配的第一个位置就是i+1
}
int flag=1;
for(int i=0;i<lent;i++)
{
if(Flag[b[i]-'a']==0)
{
flag=0;
break;
}
}
if(flag)
{
int now=0,ans=1; //now记录我们当前字符串a中匹配到了哪个位置,至少匹配一次,ans初始化1
for(int i=0;i<lent;i++)
{
now=dp[now][b[i]-'a'];
if(now==INF2) //匹配到了末尾,ans次数+1,从字符串a的0位置开始找并更新now
{
ans++;
now=dp[0][b[i]-'a'];
}
}
cout<<ans<<endl;
}
else cout<<-1<<endl;
}
}