A:CRC Tes
傻逼题意 恶心模拟
无
D:Fragmentation merging(思维)
题意:
一个长度为n的排列数组。
选取一个区间 的数作为集合A,选取一个区间 里面的数作为集合B,当两个区间的交集为空,而且A!=B 并集为C, 的元素的个数,该超级集合C就是合法的。
当我们选取的区间中l>r的时候,该集合为空集。
求集合C的数目
思路:
(感觉难点在于读懂题意)
一定要注意到当我们选取的区间中l>r的时候,该集合为空集。
这样才能推出样例
容易发现的元素的个数这个条件,你选取的区间一定是一段连续的数。
那我们直接枚举每一段区间 然后检查需要多少个区间才能拼出所枚举的区间,如果需要>2的区间才能拼出,一定是不满足的,因为我们只能选取两个集合,统计一下满足<=2的区间个数即可。
#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=3e5+10;
vector<int>ban[5010];
int a[5010];
int pos[5010];
bool res[5010];
signed main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
}
if(n==1)
{
cout<<0<<endl;
continue;
}
else
{
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
res[j]=0;
int jd=0;
for(int j=i;j<=n;j++)
{
int wz=pos[j];
if(wz==1)
{
if(res[wz+1]==0)
jd++;
}
else if(wz==n)
{
if(res[wz-1]==0)
jd++;
}
else
{
if(res[wz-1]==1&&res[wz+1]==1)
jd--;
else if(res[wz-1]==0&&res[wz+1]==0)
jd++;
}
res[wz]=1;
if(jd<=2)
{
ans++;
}
}
}
cout<<ans<<endl;
}
}
}
F:Battery
两个数列都排一下序,然后从小到大贪心的用电池。
#include<bits/stdc++.h>
#define ll long long
#define debug2(x,y) cout<<"**"<<x<<" "<<y<<endl;
using namespace std;
signed main(){
int n,m;
scanf("%d%d",&n,&m);
vector<int>a(n+1),b(m+1);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++){
scanf("%d",&b[i]);
}
sort(a.begin(),a.end());
sort(b.begin(),b.end());
int j=1;
for(int i=1;i<=n;i++){
while(a[i]&&j<=m){
if((a[i]-b[j])>=0){
a[i]-=b[j];
j++;
}
else{
break;
}
}
}
printf("%d\n",j-1);
}
H:CRC Tes(最短路)
题意:
给定一个有向图,初始边长度为1,对于每个长度小于等于3的环,环上边长度变为0。该操作可以进行多次,求最后从1号点的最短路
思路:
枚举每一个点,所能到达的长度不大于3的环,对其缩点更新距离为0,用fa[]记录更新为这个环属于同一集合。然后跑一边dijkstra,属于同一集合它们之间的距离为0。
#include <bits/stdc++.h>
// #define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 310, M = 30010;
int h[N], ne[M], e[M], idx;
int fa[N];
bool g[N][N]; // 记录a是否能到达b
int n, m;
int dist[N];
bool st[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void sd(int u)
{
vector<int>pos;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(g[fa[v]][u])//u->v->u
{
fa[v]=fa[u];
pos.push_back(v);
}
for(int j=h[v];~j;j=ne[j])
{
int c=e[j];
if(g[fa[c]][u])//u->v->c->u
{
fa[c]=fa[u];
fa[v]=fa[u];
pos.push_back(v);
pos.push_back(c);
}
}
}
for(auto v:pos)
{
for(int i=h[v];~i;i=ne[i])
{
int k=e[i];
g[fa[u]][k]=1;
}
}
}
void dijkstra()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII, vector<PII>, greater<PII>> q;
q.push({0,1});
while(q.size())
{
auto fr=q.top();
q.pop();
int u=fr.second,dis=fr.first;
if(st[u])
continue;
st[u]=true;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(st[v])
continue;
int w=1;
if(fa[v]==fa[u])
w=0;
if(dist[v]>dis+w)
{
dist[v]=dis+w;
q.push({dist[v],v});
}
}
}
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
g[a][b] = 1;
}
for (int i = 1; i <= n; i++)
fa[i] = i;
for(int i=1;i<=n;i++)
sd(i);
dijkstra();
for(int i=1;i<=n;i++)
{
if(dist[i]==0x3f3f3f3f)
cout<<-1<<" ";
else
cout<<dist[i]<<" ";
}
}
I:Sequence(单调栈)
这个问题可以转换为有个n阶2维矩阵,有些点被挖去,求有多少个矩形?
比如 1禁止出现2 3数字,那么这个矩阵g[1][2],g[1][3]会被挖去。
我们把每一个不能占据格子标1,可以的标0.
我们一行一行的枚举,可以递推出能向上延申的高度,对于每一行,从左往右扫,维护一个单调栈,栈中按高度从低到高,同时维护每个高度向右延申的长度。
每加进一个元素,弹出比他更高的元素,并合并长度。以这个点为右下角的矩形个数就是栈中所有的高度×长度之和 (来自题解)
感性的理解 枚举到的每一个格子元素向左延申都应该产生贡献(前面矩形面积之和以及自己),因为是递增的。
比如求下面这个图像有多少个完整的矩形 答案为15
手动数一数:
1*1有6个 1*2有6个 1*3有2个 2*2有1个 共15个
下面模拟一下:我们用val统计一下每一行的贡献
首先我们在第一行val=0
有一个矩阵 val+=1*1,ans+=val
接下来第二行val=0
高度为1的矩阵进栈 val+=1*1=1,ans+=val(2)
高度为2的矩阵进栈 比高度为1的矩阵高 val+=(2*1)=3这个矩阵的面积 ans+=val(5)
接一下第三行val=0
高度为2的矩阵进栈 val+=2*1=2,ans+=val(7)
高度为3的矩阵进栈 比高度为2的矩阵高 val+=(3*1)=5,ans+=val(12)
高度为1的矩阵进栈 比高度为3的低 则高度为3的pop出去 比高度为2的还低 继续pop出去,同时需要加上pop出去的矩形宽度,val值也应减去对应矩形所产生的贡献(5-2-3)=0,然后高度为1,宽为3的矩阵进栈,val+=(1*3)=3,ans+=val(15)
结束
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5010;
int g[N][N];
int h[N];//高
signed main()
{
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%lld%lld",&a,&b);
g[a][b]=1;
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(g[i][j])
h[j]=0;
else
h[j]++;
}
stack<pair<int,int>>st;
int mj=0;//面积
for(int j=1;j<=n;j++)
{
int len=1;
while(!st.empty()&&st.top().first>h[j])
{
len+=st.top().second;
mj-=(st.top().first*st.top().second);
st.pop();
}
mj+=len*h[j];
st.push({h[j],len});
ans+=mj;
}
}
cout<<ans;
}