1001 :切电线
题目大意是在街道上有无穷多个街灯编号从1开始,街灯之间是用电线相连的。但是连线是有规则的,如果街灯的编号 x 是偶数,则它与编号为 x / 2相连。如果街灯的编号 x 是奇数,那么它和 3*x+1 相连,给定n,问你站在街灯编号为 n 和 n+1 之间能剪掉多少根电线。(左边的街灯编号<=n,右边的街灯编号>n)。
数据范围如下:
由图易看出暴力枚举那一定会超时,不过一般没人会用。只需要分情况算出奇数连的线和偶数连的线相加就行了,需要找几个例子去推一下。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf ("%d",&n);
LL res = 0;
res += n - n/2; //计算偶数情况
int b = (n-1)/3+1;//计算奇数情况
if (b%2) res+=(n-b)/2+1;
else
res+=(n-b+1)/2;
printf ("%lld\n",res);
}
return 0;
}
1006:平方和
题意真是言简意赅,让你累加从1到k的平方和并凑出n,累加时每项要么乘1,要么乘-1,也就是要么加要么减,并让你输出答案。
数据范围
别提搜索,还真有人敢用,这个真是个找规律的题型,当时我们由于服务器的烦人操作已经不想写了,这题真是可惜。
见平方就相减是高中常用的忘了,相减之后你会找到规律,每相邻两项相减可以得出2,当你算算前几项,发现1,2,3都能算出来,这时想到以四为周期构造就行了。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
int k=n;
string res;
if (n%4==1) res+="1";
if (n%4==2) k+=2,res+="0001";
if (n%4==3) k-=1,res+="01";
for (int i=0;i<n/4;i++)
res+="1001";
cout<<k<<endl;
cout<<res<<endl;
}
return 0;
}
1007:二次函数
题目大意是给定一二次函数,给定范围让你求它在范围内的最小值,这时就应该想到三分法,求二次函数的极值。二分法是求一次函数的满足题意所求的性质分界点。
一个三分讲的不错的链接++++++++++++++++++++
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 1e6+10;
const LL inf = 1e18;
vector<int>mh[100];
int cul (int x)
{
int res = 0;
while (x)
{
res+=x%10;
x/=10;
}
return res;
}
void init()
{
for (int i=1;i<=N;i++)
{
int x = cul(i);
mh[x].push_back(i);
}
}
LL doit(LL x,LL A,LL B)
{
return A*x*x+B*x;
}
int main()
{
init();
int t;
scanf("%d", &t);
while (t--)
{
LL a,b,c,d,n;
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&n);
LL res = inf;
for (int i=1;i<=54;i++)
{
if (mh[i].size()==0) continue;
LL A = a*i+b;
LL B = c*i*i+d*i;
int l=0,r = upper_bound(mh[i].begin(),mh[i].end(),n)-mh[i].begin();
r--; //确保右端点在自变量范围内
if (r<0) continue;
if (A<=0) //为直线
{//极值只能在起点和终点
res = min(res,doit(mh[i][0],A,B));
res = min(res,doit(mh[i][r],A,B));
}
else
{
LL resl = inf,resr = inf;
while (l<=r)
{
int lmid = l + (r - l)/3;
int rmid = r - (r - l)/3;
resl = doit(mh[i][lmid],A,B);
resr = doit(mh[i][rmid],A,B);
if (resl<=resr)
r = rmid-1;
else
l = lmid+1;
}
res = min(res,min(resl,resr));
}
}
printf ("%lld\n",res);
}
return 0;
}
1009:命令序列
题目大意是给定一个字符串,机器人会按照字符串的指示进行上下左右的移动,让你求出能使机器人回到原点的子字符串数目。经典的子字符串想前缀和和字符串哈希,子序列想DP。
这题就是经典得出前缀和加哈希。机器人可以回到原点也就是满足向左的次数等于向右的次数并且同时向上的次数等于向下的次数。
数据范围
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
const int N = 1e5+10;
char s[N];
map<PII,int> mh;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
mh.clear();
int n;
scanf("%d", &n);
scanf("%s", s+1);
int x=0,y=0;
LL res = 0;
mh[make_pair(0,0)] = 1;
for (int i = 1; i <= n; i ++ )
{
if (s[i]=='U') x--;
else if (s[i]=='D') x++;
else if (s[i]=='L') y--;
else
y++;
res += mh[make_pair(x,y)];
mh[make_pair(x,y)]++;
}
printf ("%lld\n",res);
}
return 0;
}