Odd Palindrome
题意:判断一个字符串的所有子串是不是都是回文奇数串。
思路:枚举所有子串,如果存在偶数回文串就输出no。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
int n,t,a[N];
string st;
bool check(int l,int r)
{
for(int i=l,j=r;;i++,j--)
{
if(i==j||i>j) break;
if(st[i]!=st[r]) return false;
}
return true;
}
int main()
{
cin>>st;
for(int i=0;i<st.size();i++)
{
for(int j=i;j<st.size();j++)
{
if(check(i,j))
{ //cout<<i<<' '<<j<<endl;
if(i-j+1%2==0)
{
cout<<"Or not."<<endl;
return 0;
}
}
}
}
cout<<"Odd."<<endl;
}
B - Latin Squares
题意:判断行列不出现重复元素,判断第一行从左到右递增,第一列从上到下递增。
思路:模拟
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
typedef long long LL;
using namespace std;
int g[40][40];
LL n;
int check(int l,int r)
{
// cout<<g[l][r]<<endl;
// cout<<n<<endl;
for(int i=1;i<=n;i++)
{ //cout<<g[1][1]<<"!!!";
if(g[l][r]==g[l][i]&&i!=r) return 0;
}
for(int i=1;i<=n;i++)
{
if(g[l][r]==g[i][r]&&i!=l) return 0;
}
// cout<<l<<" ! "<<r<<endl;
return 1;
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
{
getchar();
for(int j=1;j<=n;j++)
{
char ss;
cin>>ss;
if(ss>='A'&&ss<='Z')
{
g[i][j]=int(ss-'A'+10);
}
else
{
g[i][j]=ss-'0';
}
}
}
/* for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<g[i][j];
}
cout<<endl;
}*/
int flag=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(!check(i,j))
{
flag=0;
}
}
}
if(flag==0)
{
cout<<"No"<<endl;
continue;
}
else
{
for(int i=2;i<=n;i++)
{
if(g[1][i]!=g[1][i-1]+1)
{
flag=2;
// cout<<i<<' '<<'!';
break;
}
}
for(int i=2;i<=n;i++)
{
if(g[i][1]!=g[i-1][1]+1)
{
//cout<<i<<' '<<'!';
flag=2;
break;
}
}
if(flag==1)
{
cout<<"Reduced"<<endl;
}
else if(flag==2)
{
cout<<"Not Reduced"<<endl;
}
}
}
}
C - Fear Factoring
题意:
求1-n中每一个数的所有有因子和,并将这些因子和相加。
例如 1- 3: 1的因子有1, 2的因子有1 + 2 = 3, 3的因子有1+ 3 = 4,最终答案就是 1 + 3 + 4 = 8。
补题来源
除法分块+等差序列求和来解决时间复杂度问题。
n
i
为
1
到
n
中
每
一
个
约
数
i
出
现
的
总
次
数
\frac{n}{i} 为1到n中每一个约数i出现的总次数
in为1到n中每一个约数i出现的总次数
但是直接枚举花费时间大,这里用等差数列去分块枚举。
左区间每次都是上一个右区间+1。
右区间,比如
10
/
6
=
1
,
10
/
10
=
1
10/6=1,10/10=1
10/6=1,10/10=1,对于约数为1的那些区间,我们用
10
/
1
=
10
10/1=10
10/1=10 可以直接得到右区间端点,具体看博主笔记。
#include <iostream>
#include <cstdio>
#include <algorithm>
/*
这里我们是用1~b之间额约数和 减去1 ~ a - 1之间的约数和
所以在求的时候答案可能会爆long long , 这里定义为unsigned long long
*/
typedef unsigned long long ll;
using namespace std;
ll sum(ll n)
{
ll ans = 0;
for(ll left = 1, right; left <= n; left = right + 1 )
{
right = n/(n/left);
// (left + right) * (right - left + 1) / 2 是求的等差数列和
ans += (left + right) * (right - left + 1) / 2 * (n/left);
}
return ans;
}
int main(void)
{
ll a, b;
while(cin >> a >> b)
{
cout << sum(b) - sum(a - 1) << endl;
}
return 0;
}
Halfway
题意:给一个数n,一个项目的完成是
C
n
2
C_n{2}
Cn2枚举一个从1~n的序列,从前往后,问枚举到合时,项目完成了一般的次数,输出左区间。
思路:直接模拟,先求出总次数,再用等差数列从n递减即可。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
LL n,m,k,p,x,a[N];
string st;
int main()
{
cin>>n;
LL res=0,ans;
res=n*(n-1);
res/=2;
if(res%2==0) ans=res/2;
else ans=res/2+1;
for(int i=1;i<=n;i++)
{
ans-=n-i;
if(ans<=0)
{
cout<<i<<endl;
return 0;
}
}
}
Unloaded Die
题意:一个六面的筛子得分期望为3.5,每个面出现的几率是六分之一,给定六个面特殊的概率,如果通过修改一个面的面值,达到这个筛子的期望和正常骰子期望一致,而且希望改变的面值尽可能小,求改变面值的绝对值之差。
思路:求最小改变量
△
x
△x
△x,先把当前期望算出来与3.5做个差——
△
y
△y
△y,再算出题目给的最大概率
p
p
p,最小改变量
△
x
=
△x=
△x=
△
y
p
\dfrac{△y}{p}
p△y,贪心点在如果希望改变的面值小,那么就把数值加到出现某一面概率大的一面上即可。
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
using namespace std;
double s[10];
typedef long long LL;
int main()
{
double a,b,c,d,e,f;
double mx=0;
cin>>s[1]>>s[2]>>s[3]>>s[4]>>s[5]>>s[6];
double ans=0;
for(int i=1;i<=6;i++)
{
mx=max(mx,s[i]);
ans+=i*s[i];
}
double xx=abs(3.5-ans);
double y=xx/mx;
printf("%.3lf\n",y);
}
Star Arrangements
模拟,枚举的时候需要注意题目描述的相邻出解,我的做法比较暴力。
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
typedef long long LL;
using namespace std;
double s[10];
LL n;
bool check1(int l,int r)
{
for(int i=1;;i++)
{
if((i+1)*l+(i)*r==n) return true;
if((i+1)*l+(i)*r>n) return false;
}
}
bool check2(int l,int r)
{
for(int i=1;;i++)
{
if(i*l+(i)*r==n) return true;
if(i*l+(i)*r>n) return false;
}
}
int main()
{
cin>>n;
cout<<n<<":"<<endl;
for(int i=2;i<n;i++)
{
if(check1(i,i-1)||check2(i,i-1)) cout<<i<<','<<i-1<<endl;
if(check2(i,i)||check1(i,i)) cout<<i<<','<<i<<endl;
}
}
L - Delayed Work
题意:给定k,p,x。每个工人可以工作k天,每天需要交p的罚款,每个人要交x的租金。实际需要过的天数为
k
m
\dfrac{k}{m}
mk,m为租赁的人数,该人数可以为任意值,让你挑选租赁人数,使得花费最小。
思路:假设租赁的人数为
n
n
n , 花费
c
o
s
t
=
cost=
cost=
n
⋅
x
+
k
n
⋅
p
n·x+\dfrac{k}{n}·p
n⋅x+nk⋅p,由均值不等式可知当
n
=
n=
n=
k
⋅
p
x
\sqrt{\dfrac{k·p}{x}}
xk⋅p时 , 取得最小值
2
x
⋅
k
⋅
p
2\sqrt{x·k·p}
2x⋅k⋅p。
从题的范围可以看出
n
=
n=
n=
k
⋅
p
x
\sqrt{\dfrac{k·p}{x}}
xk⋅p,最坏k和p取max,x取1.此时n=1e5。所以可以暴力枚举前1e5个数据,更新最小值即可。当然因为已知n在此点取到了最小值,也可以仅枚举
n
,
n
−
1
,
n
+
1
n,n-1,n+1
n,n−1,n+1 这三个点求最小值。
Forbidden Zero
题意:给一个数n,让你求下一个字典序递增且不含0的数。如
9
−
−
−
−
11
9----11
9−−−−11
思路:从右往左找连续个
9
9
9的个数,然后求个数的十次方和。比如
1199
1199
1199,两个
9
9
9,和就是
1
0
2
+
1
0
1
+
1
0
0
=
12
10^2+10^1+10^0=12
102+101+100=12 , 所以答案就是
1211
1211
1211。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
int n,t,a[N];
string st;
int main()
{
cin>>n;
LL m=n,res=0,ans=0;
LL p=n,ct=0;
while(p)
{
int x=p%10;
if(x!=9) break;
p/=10;
if(x==9) ct++;
}
for(int i=ct-1;i>=0;i--)
{
ans+=pow(10,i);
}
if(n%10==9)
cout<<n+ans+1;
else
cout<<n+1;
}