赞
踩
题意:找出两份名单中不同衣服大小的个总件数
解法:map模拟一下就行
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
map<string,int>mp,mp2;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
static string x;
cin>>x;
mp[x]++;
}
for(int i=1;i<=n;i++){
static string x;
cin>>x;
mp2[x]++;
}
int ans=0;
for(auto it:mp2){
if(mp[it.first]<=it.second) ans+=it.second-mp[it.first];
}
cout<<ans<<endl;
return 0;
}
题意:由程序控制n栈灯,分别在a[i]时刻转换状态,初始是亮着的。问向程序中添加一个时间点,灯的总亮着时间之和最长。
解法:枚举在每个时间点前加入一个点,然后计算灯亮的总时长。可以从后往前求出每个时间点的灯亮时间的后缀和,可以得出在第i个点加入一个点后灯亮最时长就为sum[0]-sum[i]+state+M-a[i]-sum[i]
, 其中sum[0]-sum[i]+state
表示在i点加一个点后前i时间灯亮的时间,若在i点灯亮,state=-1
,否则state=-1
;M-a[i]-sum[i]
表示后i时间在状态转变后的灯亮时间。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[100005],sum[100005];
int n,M;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>M;
for(int i=1;i<=n;i++) cin>>a[i];
a[n+1]=M;
int cur=(n+1)%2;
for(int i=n;i>=0;i--){
if(cur) sum[i]=sum[i+1]+a[i+1]-a[i];
else sum[i]=sum[i+1];
cur=1-cur;
}
// for(int i=0;i<=n;i++) cout<<sum[i]<<' ';cout<<endl;
cur=1;
int maxx=sum[0];
for(int i=1;i<=n;i++){
int temp=sum[0]-sum[i]+M-a[i]-sum[i];
if(cur) temp--;
else temp++;
maxx=max(maxx,temp);
}
cout<<maxx<<endl;
return 0;
}
题意:给n个线段的左右端点,每条线段可以覆盖从左端点到右端点的闭区间的所有点,问分别被覆盖了1~n次的点有多少个。
解法:对点坐标进行离散化,离散化的时候对于值相差大于1的两个数中间要插入一个数。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
LL cnt[maxn],a[maxn*8];
int n;
pair<LL,LL>p[maxn];
vector<LL>v;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
cin>>p[i].first>>p[i].second;
v.push_back(p[i].first);
v.push_back(p[i].second);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()), v.end());
int siz=v.size();
for(int i=0;i<siz-1;i++) if(v[i]+1!=v[i+1]) v.push_back(v[i]+1);
sort(v.begin(),v.end());
for(int i=1;i<=n;i++){
int l=lower_bound(v.begin(), v.end(), p[i].first)-v.begin();
int r=lower_bound(v.begin(), v.end(), p[i].second+1)-v.begin();
a[l]++;a[r]--;
}
siz=int(v.size());
for(int i=0;i<=siz;i++) a[i]+=a[i-1];
//for(int i=0;i<=v.size();i++) cout<<a[i]<<' ';cout<<endl;
//for(int i=0;i<siz;i++) cout<<v[i]<<' '<<a[i]<<endl;
for(int i=0;i<siz-1;i++){
cnt[a[i]]+=v[i+1]-v[i];//这里不包含v[i+1]这个点
}
cnt[a[siz-1]]++;
for(int i=1;i<=n;i++) cout<<cnt[i]<<' ';
return 0;
}
题意:如果一个array的第一个数字等于该数组长度减1,则被成为good array;一个sequence能被分成若干个good array则称为good sequence。计算原始序列的子序列中good sequence的个数
解法:看了题解才写出来的。。。
dp[i]表示以第i为开头的good sequence的个数,dp[n+1]初始化为1。从n遍历到1,如果a[i]<=0,则dp[i]=0,否则从i+a[i]+1遍历到n+1,dp[i] += dp[j]*c(a[i], j-i+1)。
dp好弱,真是个菜鸡
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=998244353;
const int maxn=1005;
int a[maxn];
LL dp[maxn],c[maxn][maxn];
int main()
{
for(int i=0;i<maxn;i++) c[0][i]=1;
for(int i=1;i<maxn;i++) c[i][0]=0;
for(int i=1;i<maxn;i++){
for(int j=1;j<maxn;j++){
c[i][j]=c[i][j-1]+c[i-1][j-1];
c[i][j]%=mod;
}
}
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
dp[n+1]=1;
for(int i=n;i>=1;i--){
if(a[i]<=0) continue;
for(int j=i+a[i]+1;j<=n+1;j++)
dp[i]=(dp[i]+dp[j]*c[a[i]][j-i-1])%mod;
}
LL ans=0;
for(int i=1;i<=n;i++) ans=(ans+dp[i])%mod;
cout<<ans<<endl;
return 0;
}
题意:在无向图中,如果把起点到终点路径上一条边删去,则不能从起点走到终点,就可以在这条边上放置一个boss,问图中任意两点之间最多放置多少个boss
解法:tarjan缩点后求树的直径
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
struct node{
int to,len;
bool operator<(const node&x)const{
return len<x.len;
}
};
const int maxn=3e5+5;
int dfs_n[maxn],low[maxn];
int dfs_clock,sccno[maxn],scc_cnt;
bool vis[maxn];
stack<int>S;
vector<int>e[maxn],e2[maxn];
queue<node>q;
int m,n;
void dfs(int u,int fa)
{
dfs_n[u]=low[u]=++dfs_clock;
vis[u]=true;
S.push(u);
for(auto v:e[u]){
if(v==fa) continue;//与有向图的区别在这
if(!dfs_n[v]){
dfs(v,u);
low[u]=min(low[u],low[v]);
}else if(vis[v]){
low[u]=min(low[u],dfs_n[v]);
}
}
if(dfs_n[u]==low[u]){
scc_cnt++;
int v=S.top();
do{
v=S.top();
S.pop();
vis[v]=false;
sccno[v]=scc_cnt;
}while(u!=v);
}
}
void tarjan()
{
for(int i=1;i<=n;i++)
if(!dfs_n[i]) dfs(i,-1);
}
node bfs(int s)
{
while(!q.empty()) q.pop();
memset(vis,0,sizeof vis);
vis[s]=true;
q.push({s,0});
node maxx={0,-1};
while(!q.empty()){
node now=q.front();
maxx=max(maxx,now);
q.pop();
int u=now.to;
for(int v:e2[u]){
if(!vis[v]){
vis[v]=true;
q.push({v,now.len+1});
}
}
}
return maxx;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
tarjan();
for(int i=1;i<=n;i++){
for(int v:e[i]){
e2[sccno[i]].push_back(sccno[v]);
}
}
cout<<bfs(bfs(1).to).len<<endl;
return 0;
}
题意:输出询问区间内只出现过一次的数中任意一个
解法:可以用莫对算法来跑,但是复杂度很高,维护只出现一次的数可以采用分块的方法。不知道为什么用链表维护会TLE
正解是线段树或者主席数。
我们用维护一个last数组,表示在当前位置,数x出现的上一个位置。线段树用来维护数x前一次出现的最小位置。如果数x已经在线段树中,就把他删除(将last置为inf),否则将last置为last[i](==-1)。
//莫对算法
//2979ms
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int block_len;
struct node{
int l,r,block,id;
node(){}
node(int l,int r,int id):l(l),r(r),id(id){
block=l/block_len;
}
bool operator<(const node&x)const{
if(block!=x.block)
return l<x.l;
if(block&1)
return r<x.r;
return r>x.r;
}
}query[maxn];
int n,q,tot;
int cnt[maxn],a[maxn],pos[maxn],b[maxn],ans[maxn];
void add(int x)
{
cnt[x]++;
if(cnt[x]==1){
tot++;
b[x/block_len]++;
}else if(cnt[x]==2){
tot--;
b[x/block_len]--;
}
}
void del(int x)
{
cnt[x]--;
if(cnt[x]==1){
tot++;
b[x/block_len]++;
}else if(cnt[x]==0){
tot--;
b[x/block_len]--;
}
}
int getans()
{
if(tot==0) return 0;
for(int i=0;;i++){
if(b[i]>0){
for(int j=i*block_len;;j++){
if(cnt[j]==1) return j;
}
}
}
}
int main()
{
scanf("%d",&n);
block_len=800;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q);
for(int i=1;i<=q;i++){
int l,r;
scanf("%d%d",&l,&r);
query[i]=node(l,r,i);
}
sort(query+1,query+q+1);
int l=1,r=0;
for(int i=1;i<=q;i++){
node &qr=query[i];
while(qr.l<l){
l--;
add(a[l]);
}
while(qr.r>r){
r++;
add(a[r]);
}
while(qr.l>l){
del(a[l]);
l++;
}
while(qr.r<r){
del(a[r]);
r--;
}
ans[qr.id]=getans();
}
for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
/
return 0;
}
//线段树
//1840ms
//还是很慢
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
const int inf=0x3f3f3f3f;
struct node{
int last,pos;
bool operator<(const node&x) const{
if(last==x.last)
return pos<x.pos;
return last<x.last;
}
}tree[maxn<<2];
struct node2{
int l,r,id;
bool operator<(const node2&x)const{
return r<x.r;
}
}query[maxn];
int a[maxn],last[maxn],ans[maxn];
int n,q;
void build(int rt,int L,int R)
{
if(L==R){
tree[rt]={inf,L};
return;
}
int mid=L+R>>1;
build(rt<<1,L,mid);
build(rt<<1|1,mid+1,R);
tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
void update(int rt,int L,int R,int pos,int last)
{
if(L==R){
tree[rt].last=last;
return;
}
int mid=L+R>>1;
if(pos<=mid)
update(rt<<1,L,mid,pos,last);
else
update(rt<<1|1,mid+1,R,pos,last);
tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
node getans(int rt,int L,int R,int l,int r)
{
if(l==L&&r==R)
return tree[rt];
int mid=L+R>>1;
if(r<=mid)
return getans(rt<<1,L,mid,l,r);
else if(l>mid)
return getans(rt<<1|1,mid+1,R,l,r);
else
return min(getans(rt<<1,L,mid,l,mid),getans(rt<<1|1,mid+1,R,mid+1,r));
}
int main()
{
ios::sync_with_stdio(false);
memset(last,-1,sizeof last);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>q;
for(int i=1;i<=q;i++){
int l,r;
cin>>l>>r;
query[i]={l,r,i};
}
sort(query+1,query+q+1);
build(1,1,n);
int cur=0;
for(int i=1;i<=q;i++){
node2 &qr=query[i];
for(int j=cur+1;j<=qr.r;j++){
if(last[a[j]]!=-1)
update(1,1,n,last[a[j]],inf);//删除这个点
update(1,1,n,j,last[a[j]]);
last[a[j]]=j;
}
node temp=getans(1,1,n,qr.l,qr.r);
//cout<<temp.last<<' '<<temp.pos<<endl;
if(temp.last==inf||temp.last>=qr.l)
ans[qr.id]=0;
else
ans[qr.id]=a[temp.pos];
cur=qr.r;
}
for(int i=1;i<=q;i++)
cout<<ans[i]<<endl;
return 0;
}
还不会,补题中。。。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。