CF题解博客:https://codeforces.com/blog/entry/69791?tdsourcetag=s_pcqq_aiomsg
补题中...
题意:
给一个序列,选出其中某几个数,满足整个序列可以被选择的某个数整除。求最少选择的数个数。
思路:
暴力枚举所有元素组合(题中值比较小)。
code:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9+7; const int maxn = 108; int a[maxn]; int cnt; bool vis[maxn]; bitset<101> bs; int main(){ int n; scanf("%d",&n); for(int i=1; i<=n; i++){ scanf("%d",a+i); } sort(a+1,a+1+n); int ans=0; int flag=0; bs.reset(); for(int i=1; i<=n; i++){ flag=0; for(int j=i; j<=n; j++){ if(a[j]%a[i]==0 && !bs[j]){ bs[j] = 1; flag = 1; } } if(flag){ ans++; } if(bs.count()==n){ printf("%d ", ans); return 0; } } printf("%d ", ans); }
题意:
给你 N 灯泡的初始状态(开或者关),然后对于每一个灯泡,给出两个值 a,b; a 代表快关状态切换的周期,b代表第一次切换的时刻。问在某一时刻,能够同时亮的灯泡数目,最多有多少。
思路:
暴力:枚举1e5所有时刻,然后统计最大值。
code:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9+7; const int maxn = 108; char s[maxn]; int a[maxn],b[maxn],c[maxn]; bitset<maxn> bs; int main(){ int n; scanf("%d",&n); scanf("%s",s+1); bs.reset(); for(int i=1; i<=n; i++){ bs[i] = s[i]-'0'; } for(int i=1; i<=n; i++){ scanf("%d%d",a+i,b+i); } int ans=0; for(int j=0; j<=30000; j++){ for(int i=1; i<=n; i++){ if( j>=b[i] && ((j-b[i])%a[i] )==0 ) { bs[i] = (int)bs[i]^1; } } ans = max(ans,(int)bs.count()); } printf("%d ", ans); }
题意:
给出一个序列,然后从中选择出两个子序列,保证 两个子序列本身 (非递减),以及保证 最后选择出的 序列 12 也呈(非递减)排列
思路:
非递减排列,子序列。很容易就想到单调栈。所以我们就先跑一边单调队列,找出所有符合条件的1。但同时还要对队列1进行处理,即找到2中的第一个元素,把所有队列1中大于2的第一个元素全部出栈,
这样就可以满足 12 也呈 非递减排列。而对于无解的情况即是,判断第一次处理好1之后剩下的序列是否呈 非递减即可。
code:
#include <cstdio> #include <queue> #include <iostream> #include <algorithm> #include <stack> #include <string> #include <cstring> using namespace std; const int maxn =2e5+7; const int inf = 0x3f3f3f3f; char arr[maxn]; stack<int>a; int top; struct node{ int val; int cur; }s[maxn]; void init(){ top = 0; s[0].val = -1; s[0].cur = -1; while(!a.empty()) a.pop(); } int main(){ int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d",&n); scanf("%s",arr); init(); for(int i=0;i<n;i++){ while(s[top].val>arr[i]-'0'){ top--; } s[++top].val = arr[i]-'0'; s[top].cur = i; } int first=-1;//最后最小位置 int cu=1; for(int i =0;i<n;i++){ if(s[cu].cur==i) cu++; else{ first = i; break; } } while(s[top].val>arr[first]-'0'&&first!=-1){ top--; } cu = 1; for(int i =0;i<n;i++){ if(s[cu].cur==i&&cu<=top) { //找到第一个最小位置 cu++; }else a.push(arr[i]-'0'); } int flag = 0; if(!a.empty()){ int now = a.top(); a.pop(); int len = a.size(); for(int i=0;i<len;i++){ int tmp = a.top(); a.pop(); if(now<tmp) { flag = 1; break; } now = tmp; } } if(flag){ puts("-"); }else{ cu = 1; for(int i =0;i<n;i++){ if(i==s[cu].cur&&cu<=top){ printf("1"); cu++; }else printf("2"); } puts(""); } } }
然后看了大佬的题解,实际上可以使用更加简单的方法。
记录一个备份序列,然后将其排序。再对原序列与排序后的序列对比,(这样就可以直接把原序列中满足条件的位置找出来,作为集合1中的值),然后再跑一遍,作为集合2中的值。如果值没有取完,则输出'-', 否则就可以直接输出 ans.
#include <iostream> #include <string> #include <algorithm> #define IOS ios::sync_with_stdio(0); cin.tie(0); using namespace std; string s,ss,ans; int main(){ IOS int T; cin>>T; while(T--){ cin>>n>>s; ss = s,ans = s; sort(ss.begin(),ss.end()); int k=0; for(int i=0;i<n;i++){ if(s[i]==ss[k]){ s[i] = '#'; k++; ans[i] = '1'; } } for(int i=0;i<n;i++){ if(s[i]==ss[k]){ s[i] = '#'; k++; ans[i] = '2'; } } if(k==n) cout<<ans<<endl; else cout<<'-'<<endl; } }