菜鸟队,只能靠补题了(无奈)。打的时候直接被1004的tle卡爆
1001. Maximum Multiple
打了个一百以内数的因子表,队友看出了规律
n|3
的时候就是(n/3)^3
n|2&&n|4
的时候就是(n/2)*(n/4)^2
1003. Triangle Partition
排个序就出来了
1011. Time Zone
把当前时间转化成UTC+0然后模拟一下就出来了
以下的都是赛后补题
1004. Distinct Values
比赛的时候没有注意到m的总和是1e6,所以一直在找o(n)的算法,结果没找到
解法也很简单。先按照区间左排序,枚举每一个区间,用set来维护有那些数字还没有被使用,设置一个右指针表示已经将ans更新到哪个位置,然后将当前区间l到下一个区间l-1的所有ans加入到set中。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node{
int l,r;
bool operator<(const node&x)const{
if(l==x.l) return r<x.r;
return l<x.l;
}
}a[maxn];
set<int>s;
int ans[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//reopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d",&a[i].l,&a[i].r);
sort(a+1,a+m+1);
for(int i=1;i<=n;i++) s.insert(i),ans[i]=1;
int r=0;
for(int i=1;i<=m;i++){
//这里不能写成if(a[i].r<=r) continue;
//这样会跳过后面最后那个循环
if(r<a[i].r)
for(int j=max(a[i].l,r+1);j<=a[i].r;j++){
ans[j]=*s.begin();
s.erase(ans[j]);
}
//将对下一个区间可以填的数加到set
for(int j=a[i].l;j<a[i+1].l;j++){
s.insert(ans[j]);
}
r=max(r,a[i].r);
}
printf("%d",ans[1]==0?1:ans[1]);
for(int i=2;i<=n;i++) printf(" %d",ans[i]==0?1:ans[i]);
puts("");
for(int i=0;i<=n;i++)
ans[i]=0;
for(int i=0;i<=m;i++)
a[i].l=a[i].r=0;
}
return 0;
}
1002. Balanced Sequence
看了杜教的题解才明白了怎么写
先用栈把每一个字符串处理一下,计算出里面已经匹配括号的数目加到答案中去,然后用一个pair存栈中剩余’)’和‘(‘的数目,然后就是排序。(a, b)表示当前字符串剩余‘)’有a个,’(‘有b个。对于两个(a, b) (c, d)
如果min(b, c)<min(a, d) (这里表示组合后对答案的贡献)则交换,否则,因为两边的括号会被浪费,所以就看那种组合浪费的少
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
const int maxn=1e5+5;
char s[maxn];
pair<int,int>p[maxn];
stack<char>S;
bool cmp(pair<int,int>& a,pair<int,int>& b)
{
if(min(a.y,b.x)==min(a.x,b.y)){
return a.x+b.y<a.y+b.x;//被放在两边的括号相当于是浪费了的
}else{
return min(a.y,b.x)>min(a.x,b.y);
}
return false;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;++i){
scanf("%s",s);
for(int j=0;s[j];++j){
if(S.empty()) S.push(s[j]);
else{
if(s[j]=='(') S.push('(');
else{
if(S.top()=='(') ans+=2,S.pop();
else S.push(')');
}
}
}
p[i].x=p[i].y=0;
while(!S.empty()){
p[i].x+=S.top()==')';
p[i].y+=S.top()=='(';
S.pop();
}
}
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++){
//cout<<p[i].x<<' '<<p[i].y<<endl;
for(int j=1;j<=p[i].x;j++){
if(S.empty()) S.push(')');
else{
if(S.top()==')') S.push(')');
else S.pop(),ans+=2;
}
}
for(int j=1;j<=p[i].y;j++){
S.push('(');
}
}
while(!S.empty()) S.pop();
printf("%d\n",ans);
}
return 0;
}
1008. RMQ Similar Sequence
看了题解和杜教的视频才抄出来的这份代码。
满足题目中的条件就是两个序列的笛卡尔树同构(菜鸡表示没听过笛卡尔树),然后求概率(完全不会推导)。
了解了一种线性求逆元的骚操作
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
LL mod=1e9+7;
LL inv[maxn];
LL ret;
int a[maxn];
int stk[maxn],l[maxn],r[maxn];
bool vis[maxn];
int n;
int dfs(int u)
{
int s=1;
if(l[u]) s+=dfs(l[u]);
if(r[u]) s+=dfs(r[u]);
ret=ret*inv[s]%mod;
return s;
}
void build()
{
for(int i=0;i<=n;i++) l[i]=r[i]=vis[i]=0;
for(int i=1,top=0;i<=n;i++){
int j=top;
while(j>0&&a[stk[j-1]]<a[i]) --j;
if(j) r[stk[j-1]]=i;
if(j<top) l[i]=stk[j];
top=j;
stk[top++]=i;
}
int root;
for(int i=1;i<=n;i++){
vis[l[i]]=true;
vis[r[i]]=true;
}
for(int i=1;i<=n;i++) if(!vis[i]) root=i;
dfs(root);
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
inv[1]=1;
for(int i=2;i<maxn;i++) inv[i]=inv[mod%i]*(mod-mod/i)%mod;
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ret=inv[2]*n%mod;
build();
printf("%lld\n",ret);
}
return 0;
}