printf("%.2lf\n",ans);
int lowbit(int x){//返回最右侧的1的位置的值
return x&(-x);//-是补码
}
我最喜欢的搜索当然要放第一个!(不是,是因为碎发那题写的我emo了)
#include
#include
using namespace std;
const int N = 30;
int tot = 0;
int n;
int a[N];
int ans;
bool vis[N] = {0};
bool dfs(int l,int now,int used,int ind){
if(used==n && (now==0)) return true;
bool f = false;
int tmpind;
for(int k=ind;k>=1;k--){
if((a[k]+now)>l) continue;
if(vis[k]) continue;//这里如果不写,就会把已经用掉的头发也考虑到去重里面,导致永远找不到答案!
else{
vis[k] = true;
if(a[k]+now==l) tmpind = n;
else tmpind = k-1;
if(dfs(l,(a[k]+now)%l,used+1,tmpind)) {
f = true;
vis[k] = false;
break;
}
vis[k] = false;
}
while(a[k-1] == a[k]) k--;
}
if(f) return true;
else return false;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
tot += a[i];
}
for(int i=1;i<=n-1;i++)
for(int j=1;j<=n-i;j++)
if(a[j]>a[j+1]) swap(a[j],a[j+1]);
// sort(a+1,a+n+1);
for(int i=a[n];i<=tot;i++){
if(tot%i) continue;
if(dfs(i,0,0,n)) {
ans = tot/i;
break;
}
}
cout<<ans<<" "<<tot/ans<<endl;
return 0;
}
超时了很多次,不是因为bubble sort(27并不大),是因为剪枝没有剪掉。
第零次剪枝:排序,从最大的发长开始搜
第一次剪枝:数量和长度除得尽
第二次剪枝:搜到大过长度 l 的就停
第三次剪枝:每次搜的一个阶段中去重(因为只选择一根头发)
第四次剪枝:倒着搜,从最长的开始搜,这样如果拼完还不够,只需从比这根头发序号更小的里面搜索(?按理说,正着搜,每次如果不够就从它开始直接往后搜应该也可以的,来不及试了)
#include
using namespace std;
int a,b,c,y1,y2,day=0;
int span,span1;
bool runn,flag;
bool run(int yr){
if(yr%4) return false;
if(yr%400==0) return true;
if(yr%100==0) return false;
return true;
}
//1850年1月1日是星期二
int add(int yue,bool runnian){
if((yue==1)||(yue==3)||(yue==5)||(yue==7)||(yue==8)||(yue==10)||(yue==12))
return 3;
if((yue==2) && runnian) return 1;
if((yue==2) && (runnian==0)) return 0;
else return 2;
}
bool check(int yr){
span1 = span;
for(int j=1;j<a;j++){
span1 += add(j,runn);
}
span1 %= 7;
// cout<<"span "<
day = (b-1)*7;
for(int j=0;j<=6;j++){
day++;
if((span1+j)%7 == c) break;
}
if((a==1)||(a==3)||(a==5)||(a==7)||(a==8)||(a==10)||(a==12))
if(day>31) return false;
if((a==4)||(a==6)||(a==9)||(a==11))
if(day>30) return false;
//这里这里这里忘写了我的妈
if((a==2) && runn)
if(day>29) return false;
if((a==2) && (runn==0) )
if(day>28) return false;
return true;
}
int main(){
cin>>a>>b>>c>>y1>>y2;
if(c==7) c=0;
span = 2;
for(int k=1850;k<y1;k++){
if(run(k)) span += 2;
else span += 1;
}
span %= 7;//1234560 0是周日
for(int i=y1;i<=y2;i++){
runn = run(i);
if(!check(i)) cout<<"none"<<endl;
else printf("%d/%02d/%02d\n",i,a,day);
if(run(i)) span += 2;
else span += 1;
span %= 7;
}
return 0;
}
忘记判30天的那一段了!!!!!!啊啊啊!!
#include
using namespace std;
int n,ans = 0;
int x,y;
int minx(int j,int k){
if(j>k) return k;
else return j;
}
int main(){
cin>>n;
cin>>x;
ans += x;
for(int i=2;i<=n-1;i++){
cin>>y;
ans += minx(x,y);
x = y;
}
ans += x;//这个x和y十分裹人,要考虑n=2的情况
cout<<ans<<endl;
return 0;
}
#include
using namespace std;
const int N = 100005;
int a[N];
int n,t;
int x;
int find(int l,int r,int k){
while(l<=r){
int mid = (l+r)>>1;
if(a[mid] <= k) l = mid+1;
else r = mid-1;
}
return r;
}
int main(){
cin>>n>>t;
for(int i=1;i<=n;i++){
cin>>a[i];
}
while(t){
cin>>x;
cout<<n-find(1,n,x)<<endl;
t--;
}
return 0;
}
其实我不太敢写二分,因为不知道什么时候+1,-1,而且return也不知道return点什么,有碰运气的感觉,还是需要仔细分析一下.
例如本题,是在排好序的数组中找到比给定数字大的数字个数,面向代码分析 :给个例子
a[1] | a[2] | a[3] | a[4] | a[5] |
---|---|---|---|---|
1 | 3 | 5 | 7 | 9 |
现在查3,4,9
3L | 3R | 3mid | 4L | 4R | 4mid | 9L | 9R | 9mid |
---|---|---|---|---|---|---|---|---|
1 | 5 | 3 | 1 | 5 | 3 | 1 | 5 | 3 |
1 | 2 | 1 | 1 | 2 | 1 | 4 | 5 | 4 |
2 | 2 | 2 | 2 | 2 | 2 | 5 | 5 | 5 |
3 | 2 | 2 | 3 | 2 | 2 | 6 | 5 | 5 |
变成两个元素以后,mid=L,如果左边一个不符合就变到右边一个,L=R=mid,如果右边一个也不符合就L=R+1,L>R,这时候返回的下标是R(R不符合,而R+1是符合的,因为右边界是R是由R+1符合而导致的);如果左边一个符合就R=mid-1=L-1,现在变成R 做法是二分时间。写的时候出事的是check函数,里面<=和>写反了…… 滑动窗口复习:无重复字母的字符子串 O(n3)…… 题目说明:只要求输出第一组解 笑死,这个题目里面说“重复次数相同”,意思是要求出现的字母出现次数必须只能多不能少!然后还有 data里面的数据是错的(。)无语了真 注意本题的特点在于:数字可以重复,导致思路变化:以head为主,tail为副,head每到一个有ans的位置时让tail去滑,滑到不能再滑了让tail回到原位,再head++,做到不重不漏。 排序,相同的数放在一起数个数 具体的AC算法可见EXAM3题解(在作业文档/大学计算机课/机考),里面有一点数学猜想与证明可以到O(logn)(我没认真看) 这是一个令人尴尬的题目……因为我做了好多遍才做过( 简单是简单,思路也很简单,每次给杯子数加1,然后等二进制分解出来的1少于等于m的时候停止,T了两个点 第二遍的代码: 把算二进制分解后的1的操作简化了,变成了模拟进位的算法,T了一个点,都是3000多ms了 最后AC的代码: 优化的想法是把1的位置存起来,只需要取用1的位置就行了,计算的时候只需要O(log2n)的复杂度 10^9*1000绝对爆int,以后做题先把可能的数字算一下 更多资料可见之前的博客 WA代码 AC代码 这是怎么一回事呢,是因为int在运算过程中会爆掉!如果右边int*int或者int+int可能会爆int,那么结果可能就会出错,应该是因为计算时是从右边往左边走的吧 笑死,改进的时候把11994
#include
1414
#include
而且第一次写还把-1的判断条件写错了……四、快速幂算法
14258
#include
五、滑动窗口
1401 经典无重复字符串滑窗O(n)
#include
see see this1405 三数和->两数和滑窗
O(n2logn)第三层用二分查找
O(n2)滑动窗口
AC代码:#include
解题思路:第一层枚举一个n,第2和3用滑窗,一个从左开始一个从右开始,和大了右指针左移,和小了左指针右移,确实可以找到答案。1418 包含全部字母的最短字串
#include
这个滑窗是相当于 tail一直往后走走到符合,然后head不断往后,每一个head算一次ans1413 正好包含不同k个数字的子序列
AC代码:#include
六、贪心
#include
and、其他小算法
摩尔投票1404
O(n)摩尔投票算法算阶乘的非零末位1385
#include
未知1、读题困难
1381(同时还有位运算)
首先的问题是题意理解,一开始以为必须是留m个杯子,每个杯子都是2k升的果汁,结果发现可以比m个杯子少(这题不是贪心),然后还是写不过,又发现每个杯子里面果汁量可以不一样多,只要都是2x就可以了。
然后就是效率问题,先看一下正确理解题意以后的第一个tle代码#include
#include
#include
其实也可以用位运算得到二进制为1的数位(请复习)
顺便 今天1024程序员节语法点:位运算lowbit
int lowbit(int x){//返回最右侧的1的位置的值
return x&(-x);//-是补码
}
未知2、你的脑子不好使
1384 前缀和,但是我下标写的很混乱
#include
未知3、几个点被坑
1、数据类型:比如说没开long long或者忘记用double——以后先考虑这个数据范围爆掉的问题,不能再错!
14277 没开long long
1359 送分题,爆double的要写高精度!
#include
54254 关于int是怎么爆掉的
#include
#include
(srds减法可能不会,因为某些二进制存储及进位的原因会抵消影响但是你不要抱着这种心理去尝试好不好)2、题目设的坑,容易惯性思维掉进去
1388 给出区间端点不一定是顺序的
未知4、一点点trick
1402(1026机考)
#include
i*x[i]*x[i]
和i*x[i]
全部存到了另外两个数组,结果全TLE了
这题的做法是:倒推,得到ans[n-1]然后四元方程组不停跑