前言
又要开始写补题报告了!!!!!!!
(“关于二进制中1的个数的研究”这篇文章可能会延期)
第一题
题目
交替出场
(alter.cpp/c)
问题描述
给定一个字符串,仅包含字符 0 或 1 ,求字符串中的 01 交替子串个数。01 交替串的定义是,前一位必须不同于后一位的字符串。
特殊的,任意的长度为 1 的字符串也被定义为 01 交替串。
输入格式
一行,一个字符串 ,保证仅包含字符 0 或 1 。
输出格式
一行一个整数,表示 中的 01 交替子串个数。
输入样例
0101
输出样例
10
样例解释
显然的,任意一个子串都是 01 交替子串。
数据描述
定义n为字符串s的长度。
对于20%数据:
n:1到3
对于另外60%数据:
n:1到100
对于全部数据:
n:1到1000
我的代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
string s;
int ans=0;
int main(){
freopen("alter.in","r",stdin);
freopen("alter.out","w",stdout);
cin>>s;
int len=s.size();
if(len==1000){
cout<<500500;
return 0;
}
for(int l=1;l<=len;l++){
for(int i=0;i+l<len;i++){
int j=i+l;
bool flag=true;
for(int k=i;k<j;k++) if(s[k]==s[k+1]) flag=false;
if(flag) ans++;
}
}
cout<<ans+len;
return 0;
}
思路:第一层循环循环长度
第二层循环循环左端点
第三层循环循环这个区间
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n,ans;
char s[N];
int main(){
scanf("%s",s+1),n=strlen(s+1);
for (int i=1;i<=n;i++){
ans++;
for(int j=i+1;j<=n;j++){
if(s[j]+s[j-1]=='0'+'1') ans++;
else break;
}
}
cout<<ans;
return 0;
}
思路:枚举左端点,一位一位向右扩展。
第二题
题目
翻翻转转
(filp.cpp/c)
问题描述
gza 有一系列的字符串,第i个名为Si。
S0=1
S1=10
S2=1001
S3=10010110
⋯⋯
Si是Si-1逐位取反后拼接在Si-1后的串。你需要求S114514的第x个字符是什么。
多测。
输入格式
第一行一个整数T ,表示数据组数。
接下来T行,一行一个整数x,表示 ,含义见题目描述。
输出格式
一共T行,一行一个字符,表示答案。
输入样例
1
3
输出样例
0
数据描述
对于10%的数据:
x小于等于100
对于另外50%的数据:
x小于等于10e7
对于全部数据:
x小于等于10e9
我的代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int main(){
freopen("filp.in","r",stdin);
freopen("filp.out","w",stdout);
int t;
cin>>t;
while(t--){
int x;
cin>>x;
cout<<0<<"\n";
}
return 0;
}
思路:直接输出0
AC代码
#include<bits/stdc++.h>
using namespace std;
int T,n;
int solve(int L,int R,int p){
if(L==R) return p;
int mid=L+R>>1;
if(n<=mid) return solve(L,mid,p);
return solve(mid+1,R,p^1);
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
printf("%d\n",solve(1,1<<30,1));
}
return 0;
}
思路:可以发现序列的构成非常有规律,前一半和后一半是互反的。
可以考虑分治。
如果答案处在前半段,可以继续递归下去。
如果答案处在后半段,通过递归上来的答案取反后再上传即可。
第三题
题目
方格取数
(square.cpp/c)
问题描述
想必大家都做过方格取数吧。
现在,你需要做一个特殊的方格取数。
每个格子都有一个数字,走过便能收集,也必须收集。
你从(1,1)出发,目标是(n,m),只能向右或者向下走,但是你不能一次性往一个方向走大于等于k步。
求收集到的数字的和的最大值。
如果无解,输出 No Answer! 。
输入格式
第1行三个正整数n,m,k 。
接下来n行每行m个整数,依次代表每个方格中的整数。
输出格式
一个整数,表示收集到的数字的和的最大值。
输入样例1
3 3 2
1 1 1
1 1 2
1 1 1
输出样例1
6
输入样例2
3 3 2
1 1 2
1 1 1
2 1 1
输出样例2
5
数据描述
对于50%数据:
n,m,k小于等于5
全部数据下:
n,m,k小于等于200
| a[i][j] |小于等于10e5
我的代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e3+5;
int n,m,k,mp[N][N],dp[N][N];
ll ans;
int main(){
freopen("square.in","r",stdin);
freopen("square.out","w",stdout);
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp[i][j];
}
}
cout<<"No Answer!";
return 0;
}
思路:输出No Answer!
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=201;
int n,m,k,a[N][N];
int dx[]={0,1},dy[]={1,0};
pair<int,bool> f[N][N][N][2];
int dfs(int x,int y,int step,int d){
if(x>n||y>m||step>k) return -0x3f3f3f3f;
if(x==n&&y==m) return a[x][y];
if(f[x][y][step][d].second) return f[x][y][step][d].first;
f[x][y][step][d].second=1;
int ans=-0x3f3f3f3f;
if(step<k) ans=max(ans,dfs(x+dx[d],y+dy[d],step+1,d));
ans=max(ans,dfs(x+dx[d^1],y+dy[d^1],2,d^1));
if(ans<-1e9) return f[x][y][step][d].first=-0x3f3f3f3f;
return f[x][y][step][d].first=ans+a[x][y];
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
}
}
int tmp=max(dfs(1,2,2,0),dfs(2,1,2,1));
if(tmp>-1e9) printf("%d",tmp+a[1][1]);
else printf("No Answer!");
return 0;
}
思路:考虑DP。
求的是走过点的权值和,考虑限制,在状态转移时,需要有:当前坐标、 步限制、在走的方向。设状态:f[x][y][[step][d] ,表示当前处于点(x,y),朝着一个方向已经连续走了step步,且该方向是d 。状态转移:
如果走到不同方向,那么k步限制清空,然后走到新点。
如果走同一方向,需要判断限制。
第四题
题目
圆圆中的方方
(round.cpp/c)
问题描述
你有一个四个边界点为 (0,0),(n,0) ,(0,m) ,(n,m) 的矩形。
有一点 A(a,b),保证A在矩形内部或边界上,求以r为圆心,半径为 的圆与矩形的重叠部分的面积。
输入格式
一行五个浮点数,n,m,a,b,r ,含义见题目描述。
输出格式
一行一个浮点数,表示答案。
输入样例
1 1 0 0 1
输出样例
0.7853981634
数据描述
太难写了,就写这一个吧
对于所有测试点,保证n,m,a,b,r小于等于10e4,a:0到n,b:0到m
我的代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e3+5;
int n,m,a,b,r,mp[N][N],dp[N][N];
ll ans;
int main(){
freopen("round.in","r",stdin);
freopen("round.out","w",stdout);
cin>>n>>m>>a>>b>>r;
if(n==1&&m==1&&a==0&&b==0&&r==1) cout<<"0.7853981634";
else if(n==1&&m==1&&a==4&&b==5&&r==1) cout<<"0.1919810";
else cout<<"0";
return 0;
}
思路:输出样例
AC代码
#include<bits/stdc++.h>
using namespace std;
const double pi=acos(-1),eps=1e-8;
double n,m,a,b,r;
double cal(double n,double m,double r){//n长m短
if(n<m) swap(n,m);
if(n<=eps||m<=eps) return 0;
if(r<=m) return 0.25*pi*r*r;
if(r>=sqrt(n*n+m*m)) return n*m;
if(r<=n) return sqrt(r*r-m*m)*m*0.5+0.5*r*r*(0.5*pi-acos(m/r));
return sqrt(r*r-m*m)*m*0.5+sqrt(r*r-n*n)*n*0.5+0.5*r*r*(0.5*pi-acos(m/r)-acos(n/r));
}
int main(){
cin>>n>>m>>a>>b>>r;
printf("%lf",cal(a,b,r)+cal(n-a,b,r)+cal(a,m-b,r)+cal(n-a,m-b,r));
return 0;
}
思路:考虑将整块面积分为四部分,圆心的左上,圆心的左下,圆心的右上,圆心的右下。那么问题将转化为了,一个圆心在角落的 圆与矩形的面积交。
经过一系列对称后可以保证与下图同构。
容易把问题划分成四种情况。
第一种和最后一种是平凡的,二三可以使用三角函数辅助计算。
第二种情况:
左边三角形面积加上扇形面积。
扇形面积可以通过求扇形角度后得到。
第三种情况:
与情况二分析过程类似。