点击打开链接codeforce#154
A
思路:水题
分析:题目要求‘B’和‘G’是交替出现,所以应该要注意判断一下男生和女生的数量,然后是先B还是先G。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
int n , m;
while(scanf("%d%d" , &n , &m) != EOF){
if(n > m){
for(int i = 0 ; i < m ; i++)
printf("BG");
int tmp = n-m;
while(tmp--)
printf("B");
}
else{
for(int i = 0 ; i < n ; i++)
printf("GB");
int tmp = m-n;
while(tmp--)
printf("G");
}
printf("\n");
}
return 0;
}
B
思路:水题
分析:
1 先注意一个事实就是不能够从后面和前面找,然后找到num[i]*2 >= num[j]满足了就认为是ans。
2 这种思想是错误的,正确的思路就是枚举每一个可能的起始值,然后求当前要删除的个数,最后得到最少的值即可。
3 那么我们就应该要先排序,然后是一个有序的序列,我们可以利用维护一个指针j,j是不用回溯的,因为随着i的增大,num[i]*2 >= num[j]肯定是满足的。所以复杂度完全可以接受。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100010
int main(){
int n;
int num[MAXN];
while(scanf("%d" , &n) != EOF){
for(int i = 0 ; i < n ; i++)
scanf("%d" , &num[i]);
sort(num , num+n);
int ans = 0xFFFFFFF;
int j = 0;
for(int i = 0 ; i < n ; i++){
if(i && num[i-1] == num[i])
continue;
for(; j < n ; j++){
if(num[i]*2 < num[j])
break;
}
int tmp = i+n-j;
ans = min(ans , tmp);
}
cout<<ans<<endl;
}
return 0;
}
C
思路:bfs 或 枚举中间行
分析:
1 bfs的时候要注意判断什么时候不满足
2 枚举中间行的做法应该注意如果从r1->i->r2后现在没有改变当前所在的列那么应该是c1->c2,这个地方注意。
代码:
//bfs
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 110
int n;
int Sx , Sy , Ex , Ey;
int num[MAXN];
bool vis[MAXN][100000];
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
struct Node{
int x;
int y;
int step;
};
queue<Node>q;
int BFS(){
while(!q.empty())
q.pop();
memset(vis , false , sizeof(vis));
Node tmp;
tmp.x = Sx , tmp.y = Sy , tmp.step = 0;
vis[Sx][Sy] = true;
q.push(tmp);
while(!q.empty()){
tmp = q.front();
q.pop();
if(tmp.x == Ex && tmp.y == Ey)
return tmp.step;
int x , y;
for(int i = 0 ; i < 4 ; i++){
x = tmp.x+dir[i][0];
y = tmp.y+dir[i][1];
if(x < 1 || x > n)
continue;
//注意判断y是否满足
if(y < 1 || dir[i][1] && y > num[tmp.x])
continue;
//求出具体的点(y肯定是小的那一个)
y = min(y , num[x]);
if(vis[x][y])
continue;
vis[x][y] = true;
Node tmpNode;
tmpNode.x = x;
tmpNode.y = y;
tmpNode.step = tmp.step+1;
q.push(tmpNode);
}
}
}
int main(){
while(scanf("%d" , &n) != EOF){
for(int i = 1 ; i <= n ; i++){
scanf("%d" , &num[i]);
num[i]++;//最末尾位置可以用
}
scanf("%d%d%d%d" , &Sx , &Sy , &Ex , &Ey);
printf("%d\n" , BFS());
}
return 0;
}
//枚举中间行
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 110
int n;
int num[MAXN];
int R1 , C1 , R2 , C2;
int main(){
while(scanf("%d" , &n) != EOF){
for(int i = 1 ; i <= n ; i++){
scanf("%d" , &num[i]);
num[i]++;
}
scanf("%d%d%d%d" , &R1 , &C1 , &R2 , &C2);
int ans = 1<<30;
for(int i = 1 ; i <= n ; i++){
int MIN , min1 , min2;
if(i < R1)
min1 = *min_element(num+i , num+R1+1);
else
min1 = *min_element(num+R1 , num+i+1);
if(i < R2)
min2 = *min_element(num+i , num+R2+1);
else
min2 = *min_element(num+R2 , num+i+1);
MIN = min(min1 , min2);
MIN = min(C1 , MIN);//这里还要和C1做一下比较
int tmpAns = abs(R1-i)+abs(R2-i)+abs(MIN-C2);
ans = min(ans , tmpAns);
}
cout<<ans<<endl;
}
return 0;
}
D
题意:
1 给定一个n*m的矩阵每个格子有一个字母,现在要求有多少的子矩阵满足四个角的字母相同并且这个子矩阵的字母的个数不大于k
分析:
1 首先利用o(n*m)的时间求出每个点到左上角这个矩阵字母'a'的个数
2 枚举子矩阵的起始行和末尾行,如果直接枚举列总的时间复杂度是O(n^2*m^2)效率肯定是不行的。我们需要把时间优化到O(x*n^2*m),x是常数。
我们利用vector记录每个字母在每一行中的位置,然后对于同一行来说越后面总的子矩阵的'a'的个数越来越多,我们可以利用二分,最后总的时间复杂度为O(logm*n^2*m)
代码:
#include<set>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long int64;
const int MAXN = 410;
const int N = 26;
int n , m , k;
int sum[MAXN][MAXN];
char mat[MAXN][MAXN];
vector<int>v[N];
void clear(){
for(int i = 0 ; i < N ; i++)
v[i].clear();
}
bool isOk(int r1 , int r2 , int c1 , int c2){
int num = sum[r2][c2]-sum[r2][c1-1]-sum[r1-1][c2]+sum[r1-1][c1-1];
return (num <= k);
}
int64 getSub(int x , int r1 , int r2 , int c){
int64 ans = 0;
int left = 0;
int right = v[x].size()-1;
while(left < right){
int mid = (left+right)>>1;
if(isOk(r1 , r2 , v[x][mid] , c)){
ans += right-mid;
right = mid;
}
else
left = mid+1;
}
return ans;
}
int64 solve(){
int64 ans = 0;
memset(sum , 0 , sizeof(sum));
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= m ; j++)
sum[i][j] = sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+(mat[i][j] == 'a');
// begin and end row
for(int i = 1 ; i <= n ; i++){
for(int j = i+1 ; j <= n ; j++){
clear();
// col
for(int c = 1 ; c <= m ; c++){
// 两点相等
if(mat[i][c] == mat[j][c]){
v[mat[i][c]-'a'].push_back(c);
ans += getSub(mat[i][c]-'a' , i , j , c);
}
}
}
}
return ans;
}
int main(){
while(scanf("%d%d%d%*c" , &n , &m , &k) != EOF){
for(int i = 1 ; i <= n ; i++)
gets(mat[i]+1);
cout<<solve()<<endl;
}
return 0;
}
E
题意:
1 有一个打印机每秒钟只能打印一页,现在有n个任务,每个任务有一个到来的时间t,以及这个任务要打印的页数s,还有打印的优先级p
2 现在我们知道n-1任务的优先级,还有一个不知道,但是这个不知道的任务我们知道它完成打印的时间T,问这个不知道的认为的优先级
分析:
1 对于给定的优先级,我们可以求出所有的任务的结束时间。
2 我们已经知道了n-1个任务的优先级,那么我们可以利用二分来求未知任务的优先级,然后根据结果进行判断。
3 求所有任务的结束时间,我们只要维护一个优先队列即可。
代码:
#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long int64;
const int INF = 1e9;
const int MAXN = 50010;
struct Node{
int t;
int s;
int p;
int id;
bool operator<(const Node& tmp)const{
return p < tmp.p;
}
};
int n , pos , maxP;
int64 T;
int64 ans[MAXN];
Node node[MAXN];
Node tmpNode[MAXN];
map<int64 , int>mp;
bool cmp(const Node& a , const Node& b){
if(a.t < b.t)
return true;
else if(a.t == b.t && a.p > b.p)
return true;
return false;
}
int64 getTime(int p){
memcpy(tmpNode , node , sizeof(node));
tmpNode[pos].p = p;
sort(tmpNode , tmpNode+n , cmp);
priority_queue<Node>q;
int i = 1;
int64 time = tmpNode[0].t;
int64 val;
q.push(tmpNode[0]);
// push n tmpNodes
while(!q.empty() || i < n){
Node tmp;
if(!q.empty()){
tmp = q.top();
q.pop();
}
else{
time = tmpNode[i].t;
q.push(tmpNode[i++]);
continue;
}
if(i >= n){
time += tmp.s;
ans[tmp.id] = time;
if(tmp.id == pos)
val = time;
continue;
}
int t = tmpNode[i].t-time;
if(tmp.s > t){
tmp.s -= t;
q.push(tmp);
q.push(tmpNode[i]);
time = tmpNode[i++].t;
}
else{
time += tmp.s;
ans[tmp.id] = time;
if(tmp.id == pos)
val = time;
}
}
return val;
}
void solve(){
// binary search
int left = 1;
int right = maxP+1;
int ansp = -1;
while(left < right){
int mid = (left+right)>>1;
int64 time = getTime(mid);
if(time == T && mp[mid] == 0){
ansp = mid;
break;;
}
else if(time < T)
right = mid;
else
left = mid+1;
}
if(ansp == -1){
ansp = left;
getTime(left);
}
cout<<ansp<<endl<<ans[0];
for(int i = 1 ; i < n ; i++)
cout<<" "<<ans[i];
puts("");
}
int main(){
while(scanf("%d" , &n) != EOF){
maxP = 0;
mp.clear();
for(int i = 0 ; i < n ; i++){
scanf("%d%d%d" , &node[i].t , &node[i].s , &node[i].p);
node[i].id = i;
maxP = max(maxP , node[i].p);
mp[node[i].p] = 1;
if(node[i].p == -1)
pos = i;
}
cin>>T;
solve();
}
return 0;
}
分享到:
相关推荐
Codeforces Round #723 (Div. 2).md
上面代码跑出来的dp[n][m]是0,然后从(1,1)(1,2)(2,2)(2,3)这样的相与值是k (看懂ans+k是啥应该就懂了) 代码: int main() { std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int ans=(1&...
传送门 题意: 开始位置在0,问能否跳到n+1位置 每步只能跳d 在1——n每个位置有方向,L,R,求d的最小值 思路: 只用找相邻两个R之间的最大值即可 代码: #include #include ...typedef long long l
就是把所有相等的数放到一个vector里,如果他出现大于2次,看最远的间距是否大于2即可,找到一个就可以 代码: #include #include #include #include #include #include #include #include #include #include #...
长度为n的字符串包含n−2n−2n−2个aaa和222个bbb,求按照字典序排列输出第kkk个字符串 解题思路 第一个bbb在倒数第二位有1个字符串,在倒数第三位有2个字符串…在倒数第nnn位时有n−1n-1n−1个字符串 可以根据第一...
E. Cyclic Components 题目链接-E. Cyclic Components 题目大意 给你nnn个点和mmm条边,求所构成图中单圈环的个数 ...并查集并查集并查集 很明显单圈环每个点的度都为222,所以我们可以用数组cnt[]记录每个点的度,...
Codeforces Round #629 (Div. 3) E.Tree Queries (DFS) 思路:若ai 在路径上 ,则ai的父结点一定在路径上,若ai是路径上某个结点的子结点,则ai的父结点一定在路径上,综上只需考虑ai的父节点就行了。对每个ai判断...
给两两节点放一个数字(0~n-2 唯一) 给你一棵树,求所有任意两节点相连的路以外的路上的数字的最小值最小 思路 构造 若一个点连了三条边及以上,则这个点的边从最小值开始赋值。其他边从最大点开始赋值。 证明:一...
给一个长度为n的数组,两种操作,一个是把任意一个ai变成ai+2a_i变成a_i+2ai变成ai+2,另一个是如果所有数都大于0,可以把所有数减1,问通过这些操作能否把所有数变为0 思路: 如果任意两个数之差为奇数,那么就...
输入一个正整数x,找出这样的2个正整数a和b,使得gcd(a,b)+lcm(a,b)=x 解题思路 找最特殊的情况a=1,b=x-1即可 这样a,b两个数最大公因数为1,最小公倍数x-1,满足题意√ 附上代码 #include #define int long long #...
B. Longest Palindrome time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard output Returning back to problem solving, Gildong is now studying about ...
将所有数字看成2进制,从最高位看起,如果第i位上为1的数只有一个的话,那么这个数必然对答案有贡献,就把它排在第一个,后面任意排。 例:11,6,4,0 二进制表示为:1011,110,100,0 右起第四位为1的只有1011,...
传说门 刚好今晚是中国场! 其实这道题比较水,但当时思路错,一心想着化简公式,浪费了好多时间a....#pragma GCC optimize(2) #include #define ll long long #define endl '\n' using namespace std; const int manx=
C(n-2,i-1)*C(j-1,n-2)*(i-1) __ j: n-1 -> m 我们发现内层循环,每次只是j加一,我们就可以只用一次组合数剩下的用差量表示 对于外层循环同理 只有(i-1) * C(n-2,i-1) i会每次加一。我们也只算一次剩下的用差量...
传送门 题意: 找规律,题意就是有多少种方式填充该图形 画两个就发现,输出n即可 代码: #include #include #include #include #include #include #include #include ...#define SZ(x) ((int)(x)
A #include using namespace std; typedef long long ll; int main(){ int t; cin>>t; while(t--){ ll x; cin>>x; cout<<1>>t; while(t--){ st.clear(); ll n; cin >>n;... ll re
题目链接:B. Longest Palindrome 题目 Returning back to problem solving, Gildong is now studying about palindromes. He learned that a palindrome is a string that is the same as its reverse....
惭愧,前几天刚学的dfs序判祖先关系都忘了用。。 这题我们先把所有点都变成父亲节点(根节点不变),这样只需要判所有节点是否在一条链上。 由于判断x是y的祖先:需要满足:st[x]<...const int M = 2e5+