《牛客直播课习题1》
前言:随缘更新,水题不写.
题目:奇♂妙拆分
思路:
很显然是个质因子分解的思路。
map统计下没被分解过的因子即可.
Code:
#include<iostream> #include<stdio.h> #include<queue> #include<algorithm> #include<math.h> #include<stack> #include<map> #include<limits.h> #include<vector> #include<string.h> #include<string> using namespace std; typedef long long LL; typedef pair<double,double> pii; const int N = 5e5+5; const int M = 1005; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) int main() { int t;sd(t); while(t--) { int n;sd(n); int m = sqrt(n),ans = 1; map<int,int> mp; mp[1]++; for(int i=2;i<=m;++i) { if(n == 1) break; if(n%i == 0 && mp[i] == 0) { mp[i]++;ans++; n /= i; } } if(mp[n] == 0) ans++; pr(ans); } // system("pause"); return 0; }
题目:国王的游戏
思路:
#include<bits/stdc++.h> using namespace std; #define INF INT_MAX #define INM INT_MIN typedef long long LL; typedef pair<int,int> pii; const int N = 1e4+5; int ans[N],sum[N] = {0,1},last[N] = {0,1},len1 = 1,len2 = 1,lenla = 1; struct Node { int x,y; LL add; }p[N]; bool cmp(Node a,Node b) { return a.add < b.add; } void bigc(int x) { int tmp = 0; for(int i=1;i<=len1;++i) { sum[i] *= x; } for(int i=1;i<=len1;++i) { tmp += sum[i]; sum[i] = tmp%10; tmp /= 10; } while(tmp != 0)//位数增加 { len1++; sum[len1] = tmp%10; tmp /= 10; } } void divition(int x) { memset(ans,0,sizeof(ans)); int tmp = 0; len2 = len1; for(int i=len1;i>=1;--i)//从高位开始,保证tmp不会太大,从而完成模拟 { tmp *= 10;//模拟除法 tmp += sum[i]; if(tmp >= x)//可以除了 { ans[i] = tmp/x;//这里是除去,不再是取余了,因为是除法.. tmp %= x; } } while(ans[len2] == 0)//去除前缀0 { if(len2 == 1) break;//本身为1时 len2--; } } void Compare() { if(len2 > lenla)//大,要交换 { for(int i=1;i<=len2;++i) { last[i] = ans[i]; } lenla = len2;//长度也要变 } else if(len2 == lenla) { for(int i=len2;i>=1;--i)//从高位开始比较 { if(ans[i] > last[i]) { for(int j=1;j<=len2;++j) { last[j] = ans[j]; } lenla = len2; } } } } int main() { ios::sync_with_stdio(false); int n; cin >> n >> p[0].x >> p[0].y; for(int i=1;i<=n;++i) { cin >> p[i].x >> p[i].y; p[i].add = p[i].x*p[i].y; } sort(p+1,p+n+1,cmp); for(int i=1;i<=n;++i) { bigc(p[i-1].x); divition(p[i].y); Compare(); } for(int i=lenla;i>=1;--i) cout << last[i]; cout << endl; }
题目:校门外的树:
解法1:直接上线段树.
Code:
#include<iostream> #include<stdio.h> #include<queue> #include<algorithm> #include<math.h> #include<stack> #include<map> #include<limits.h> #include<vector> #include<string.h> #include<string> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const int N = 3e4+5; const int M = 1005; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) struct Node{int L,r,val,tag;}node[N<<2];//val记录树的个数,0-没砍,1-砍了. void Pushup(int idx){node[idx].val = node[idx<<1].val+node[idx<<1|1].val;} void Pushdown(int idx) { if(node[idx].tag == 1) { node[idx<<1].val = node[idx<<1|1].val = 0; node[idx<<1].tag = node[idx<<1|1].tag = 1; node[idx].tag = 0; } } void build(int L,int r,int idx) { node[idx].L = L,node[idx].r = r,node[idx].tag = 0; if(L == r) { node[idx].val = 1; return ; } int mid = L+r>>1; build(L,mid,idx<<1);build(mid+1,r,idx<<1|1); Pushup(idx); } void update(int L,int r,int idx) { if(node[idx].L >= L && node[idx].r <= r) node[idx].val = 0,node[idx].tag = 1; else { int mid = node[idx].L+node[idx].r>>1; Pushdown(idx); if(mid >= L) update(L,r,idx<<1); if(mid < r) update(L,r,idx<<1|1); Pushup(idx); } } int query(int L,int r,int idx) { if(node[idx].L >= L && node[idx].r <= r) return node[idx].val; int mid = node[idx].L+node[idx].r>>1,ans = 0; Pushdown(idx); if(mid >= L) ans += query(L,r,idx<<1); if(mid < r) ans += query(L,r,idx<<1|1); return ans; } int main() { int L,m;sdd(L,m); build(0,L,1); while(m--) { int x,y;sdd(x,y); update(x,y,1); } int ans = query(0,L,1); pr(ans); //system("pause"); return 0; }
解法2:差分.
这里有重复的,但是要明白差分是不会影响到差分那段之外的。
只会让原来的那段更大而已。那么就很简单了。如果某段砍去,那就让这段里的树都加上1.
如果有重复,那只会>1.所以我们只需要统计0的个数,就是还在的树.
Code:
#include<iostream> #include<stdio.h> #include<queue> #include<algorithm> #include<math.h> #include<stack> #include<map> #include<limits.h> #include<vector> #include<string.h> #include<string> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const int N = 3e4+5; const int M = 1005; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) int s[N]; int main() { int L,m;sdd(L,m); while(m--) { int x,y;sdd(x,y); s[x]++,s[y+1]--; } for(int i=0;i<=L;++i) s[i] += s[i-1]; int ans = 0; for(int i=0;i<=L;++i) if(s[i] <= 0) ans++; pr(ans); // system("pause"); return 0; }
题目:拼数
思路:贪心。
证明:
可以将每个数看成一个字符串。那么对于最终的答案,就是求字典序最大的数(这里的字典序大定义为数大.不是abcd那种).
那么先从相邻的两个字符串s1,s2入手。
我们按照s1+s2 和 s2+s1里较大的那个排序,求得了这两个字符相连后的较大的字典序.
那么这样映射到全局,对于所有的相邻的,都按照这样的思路来排序,就能使得所有的相连后的字典序最大.
Code:
#include<iostream> #include<stdio.h> #include<queue> #include<algorithm> #include<math.h> #include<stack> #include<map> #include<limits.h> #include<vector> #include<string.h> #include<string> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const int N = 3e4+5; const int M = 1005; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) bool cmp(string a,string b) { return a+b > b+a; } int main() { int n;sd(n); string s[20]; for(int i=1;i<=n;++i) cin >> s[i]; sort(s+1,s+n+1,cmp); for(int i=1;i<=n;++i) cout << s[i]; // system("pause"); return 0; }
.题目:Selfish Grazing
思路:贪心.
首先思考到当前的位置,右边界r肯定是要越小越好.
那么我让每一个的右边界都尽量小,可知按右边界从小到大排序为最优思路。
为什么不是按左边界?因为我们从头开始扫,对于当前的点能和一下产生矛盾的只有右边界。
如果从尾部开始扫的话,就可以按左边界排序.
Code:
#include<iostream> #include<stdio.h> #include<queue> #include<algorithm> #include<math.h> #include<stack> #include<map> #include<limits.h> #include<vector> #include<string.h> #include<string> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const int N = 1e5+5; const int M = 1005; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) struct Node{int L,r;}p[N]; bool cmp(Node a,Node b) { if(a.r == b.r) return a.L > b.L; return a.r < b.r; } int main() { int n;sd(n); for(int i=1;i<=n;++i) sdd(p[i].L,p[i].r); sort(p+1,p+n+1,cmp); int ans = 1,r = p[1].r; for(int i=2;i<=n;++i) { if(r <= p[i].L) ans++,r = p[i].r; } pr(ans); //system("pause"); return 0; }
题目:值周
思路:
首先可以直接暴力差分,因为数据不够强..
我一开始的思路是将所有点排序后,按每段区间来离散化.
但是T了?复杂度算了下应该不会爆..不知道什么原因.
正解:离散化+差分.
因为L到达了1e8,但是m比较小。
所以可以离散化。
将每段区间按左边界从小到大,右边界从小到大排序。
用删树的思路。开始我们的值为所有的树.
然后从头开始遍历离散化后的区间
对于当前离散化到的区间。
假定为[L,r].
如果它的r > 下一个区间的r,那么在之前对[L,r]区间内的删边操作中,肯定已经将下一个区间里的树都删完了。
如果它的r < 下一个区间的r,那么说明区间内有没删的树。那么找到左边界max(p[i].L,la]。因为如果la > p[i].L,那么肯定要取la,这样保证不会重复删树.
然后删去p[i].r-l+1的树,然后r值继续推移到p[i].r+1,加1保证不会重复删.
Code:
#include<iostream> #include<stdio.h> #include<queue> #include<algorithm> #include<math.h> #include<stack> #include<map> #include<limits.h> #include<vector> #include<string.h> #include<string> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const int N = 1e6+5; const int M = 1005; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } struct Node{int L,r;}p[N]; bool cmp(Node a,Node b) { if(a.L == b.L) return a.r < b.r; return a.L < b.L; } int main() { int L,m; L = read();m = read(); for(int i=1;i<=m;++i) { p[i].L = read(),p[i].r = read(); } sort(p+1,p+m+1,cmp); int ans = L+1,la = 0; for(int i=1;i<=m;++i) { if(la <= p[i].r) { int sl = max(p[i].L,la); ans -= p[i].r-sl+1; la = p[i].r+1; } } pr(ans); //system("pause"); return 0; }
题目:切长条
思路:
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const int N = 1e6+5; const int M = 1005; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) struct Node{int L,r;}p[N]; bool cmp(Node a,Node b) { if(a.L == b.L) return a.L < b.L; return a.r < b.r; } int main() { int n;sd(n); for(int i=1;i<=n;++i) { int x,y;sdd(x,y); p[i].L = x,p[i].r = p[i].L+y-1;//一个数字代表一个长度 } sort(p+1,p+n+1,cmp); int ans = 1,lr = p[1].r; for(int i=2;i<=n;++i) { if(p[i].L > lr) ans++,lr = p[i].r; } pr(ans); //system("pause"); return 0; }
题目:Flip Game
思路:
基本状压题.主要在于代码简化。
可以将查找函数写成两个字符串的形参形式来简化代码。
Code:
#include<iostream> #include<stdio.h> #include<queue> #include<algorithm> #include<math.h> #include<stack> #include<map> #include<limits.h> #include<vector> #include<string.h> #include<string> using namespace std; typedef long long LL; typedef pair<double,double> pii; const int N = 2e5+5; const int M = 1e6+5; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) string mp[5]; char st[5][5]; int vis[5][5],ans = INF;//vis表示有没有翻转过. void update_same(int i,char c1,char c2)//同一行内更新,c1-目标,c2-不满足的 { for(int j=0;j<4;++j) { int tmp = vis[i][j]+vis[i][j+1]; if(j != 0) tmp += vis[i][j-1]; if(i != 0) tmp += vis[i-1][j]; tmp %= 2; if((st[i][j] == c1 && tmp == 0) || (st[i][j] == c2 && tmp == 1)) st[i][j] = c1; else st[i][j] = c2; } } bool check(int i,int j,char c1) { if(st[i-1][j] == c1) return true; return false; } void slove(char c1,char c2) { for(int i=0;i<(1<<4);++i) { int tmp = 0; for(int j=0;j<4;++j) for(int k=0;k<4;++k) st[j][k] = mp[j][k]; met0(vis); for(int j=0;j<4;++j) { int sta = ((i>>j)&1); if(sta == 1) vis[0][j]++,tmp++; } update_same(0,c1,c2); for(int j=1;j<4;++j) { for(int k=0;k<4;++k) { if(!check(j,k,c1)) vis[j][k]++,tmp++; } update_same(j,c1,c2); } bool f = 0; for(int j=0;j<4;++j) if(st[3][j] != c1){f = 1;break;} if(!f) ans = min(ans,tmp); } } int main() { for(int i=0;i<4;++i) cin >> mp[i]; //全白 slove('b','w'); slove('w','b'); if(ans == INF) printf("Impossible\n"); else pr(ans); // system("pause"); return 0; }
题目:「土」巨石滚滚
思路:
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<double,double> pii; const int N = 5e5+5; const int M = 1e5+5; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) struct Node{int a,b,c;}p[N]; bool cmp(Node a,Node b) { if(a.c >= 0 && b.c >= 0) return a.a < b.a; else if(a.c < 0 && b.c < 0) return a.b > b.b; return a.c > b.c; } int main() { int t;sd(t); while(t--) { int n,m;sdd(n,m); for(int i=1;i<=n;++i) { sdd(p[i].a,p[i].b); p[i].c = p[i].b-p[i].a; } sort(p+1,p+n+1,cmp); LL tmp = m; bool f = 0; for(int i=1;i<=n;++i) { tmp -= p[i].a; if(tmp < 0) { f = 1; break; } tmp += p[i].b; } if(f) printf("No\n"); else printf("Yes\n"); } system("pause"); return 0; }