Camp算法刷题记录1

Camp

文章目录

        • Camp
          • day1
          • day2
          • day3
          • day4
          • 107 饿饿饭饭
          • 201
          • 202
          • 203 最大和上升子序列
          • 205 跳跳
          • 106 订单编号
          • 206 异或和或
          • 207 01序列
          • 加一
          • 302 序列维护
          • 305删删
          • 饿饿饭饭2
          • 401子串分支和
          • 402
          • 锦标赛(思维题哇)
          • 404 可重排列

day1

输入n,输出n行n列的由+.组成的正方形,其中最外面一圈全是+,第二圈全是.,…,对于第ii圈,如果ii是奇数,那么全是+,否则全是.

void solve(){
	int n,x;
	cin>>n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			int minn=n;
			x=i;
			minn=min(x,minn);
			x=n+1-i;
			minn=min(x,minn);
			x=j;
			minn=min(x,minn);
			x=n+1-j;
			minn=min(x,minn);
			if(minn%2==1) a[i][j]='+';
			else a[i][j]='.';
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j)
		cout<<a[i][j];
		cout<<endl;
}
}

my reward:对于任何一个点,通过比较他和最上面,最下面,最左边,最右边,这四个值的最小值,即能判断他是第几圈

day2

楼梯有 n阶,上楼可以一步上一阶,也可以一步上二阶。

但你不能连续三步都走两阶,计算走到第n阶共有多少种不同的走法。

#include 
#include 
#include 
using namespace std;
long long int dp[110][3];
void solve(){
	int n;
	long long sum=0;
	cin>>n;
	dp[1][0]=1;
	dp[2][1]=1;
	dp[2][0]=1;
	for(int i=3;i<=n;++i){
		for(int j=0;j<3;++j)
		dp[i][0]=dp[i][0]+dp[i-1][j];
		dp[i][1]=dp[i][1]+dp[i-2][0];
		dp[i][2]=dp[i][2]+dp[i-2][1];
	}
	for(int i=0;i<3;++i) sum+=dp[n][i];
	cout<<sum; 
}
int main(void) {
//int n;
//dp[0]=1;
//dp[1]=1;
//cin>>n;
//for(int i=2;i<=n;++i){
//	dp[i]=dp[i-1]+dp[i-2];
//	if(i>6) dp[i]=dp[i]-dp[i-7];
//	if(i==6) dp[i]--;
//}
//cout<
solve();
return 0;
}

my reward:

1.找规律其实挺难找的,找了n年

2. d p [ i ] [ j ] dp[i][j] dp[i][j]表示走到第i层时连续跳两层了j次 则 d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 1 ] + d p [ i − 1 ] [ 2 ] dp[i][0]=dp[i-1][0]+dp[i-1][1]+dp[i-1][2] dp[i][0]=dp[i1][0]+dp[i1][1]+dp[i1][2] 因为是连续的嘛,所以从上一层跳过来只能跳一层,所以j肯定变为0了。

day3

有一条很长的数轴,一开始你在00的位置。接下来你要走n步,第i步你可以往右走ai或者bi。

问n步之后,0到m的每个位置,能不能走到?

#include 
#include 
#include 
using namespace std;
const int N=1e5+5;
int f[110][N];
int a[110],b[110]; 
int main(void) {
int n,m;
f[0][0]=1;
cin>>n>>m;
for(int i=1;i<=n;++i){
	cin>>a[i]>>b[i];
}
for(int i=1;i<=n;++i){
	for(int j=1;j<=m;++j){
		if(j>=a[i]){
			if(f[i-1][j-a[i]]) f[i][j]=1;
		}
		if(j>=b[i]){
			if(f[i-1][j-b[i]]) f[i][j]=1;
		}
	}
}
for(int i=0;i<=m;++i){
	if(f[n][i]) cout<<1;
	else cout<<0;
}
return 0;
}

my reward: f [ i ] [ j ] f[i][j] f[i][j]表示第几步能否走到j,若为1表示能走到,想到其实也挺easy的

一维的怎么写

for(int i=1;i<=n;++i){
	for(int j=m;j>=0;--j){
		int flag=0;
		if(j>=a[i]){
			if(f[j-a[i]]) {
				f[j]=1;
				flag=1;
			}
			else f[j]=0;
		}
		if(j>=b[i]&&flag==0){
			if(f[j-b[i]]) f[j]=1;
			else f[j]=0;
		}
		if(j<a[i]&&j<b[i]) f[j]=0;	
	}
	if(i==1) f[0]=0;
}
for(int i=0;i<=m;++i){
	if(f[i]) cout<<1;
	else cout<<0;

reward:刚开始不开flag,就寄了,因为假如你满足了a,f[j]变成了1,但是你不满足b,f[j]就变回0了

day4
#include 
#include 
#include 
#include 
using namespace std;
map<string,int>people;
map<string,int>score;
int main(void) {
int n,m,k,s1;
string s,x,y;
cin>>n>>m>>k;
while(n--){
	cin>>s;
	people[s]=1;
}
while(m--){
	cin>>s>>s1;
	score[s]=s1;
}
while(k--){
	cin>>s>>x>>y;
	if(people[s]&&y=="AC") people[s]=people[s]+score[x];
}
map<string,int>::iterator it;
//map >::iterator it;
//for(it=people.begin();it!=people.end();it++){
//	if(it->second==0) continue;
//	cout<first<<" "<second-1<
//}
for(auto a:people){
	if(a.second!=0)  //敲重点!!!!!map循环遍历用second,first控制
	cout<<a.first<<" "<<a.second-1<<endl;
} 
return 0;
}
//这个写法没考虑到map会按键进行排序,所以输出的时候没按题中输入顺序输出,所以考虑在map前面在加一个参数来记录输入顺序




#include  
using namespace std;
map<int,map<string,int> >people;
map<string,int>score;
int main(void){
	int n,m,k;
	int score1;
	string str,str1,str2;
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i) {
		cin>>str;
		people[i][str]=1;//敲重点
	}
	for(int i=1;i<=m;++i){
		cin>>str>>score1;
		score[str]=score1;
	}
	while(k--){
		cin>>str>>str1>>str2;
		if(str2=="AC"){
			for(int i=1;i<=n;++i){
				if(people[i][str]>0){
					people[i][str]+=score[str1];
					break;
				}
			}
		}
	}
	for(int i=1;i<=n;++i){
		for(auto t:people[i]){
			if(t.second>0) cout<<t.first<<" "<<t.second-1<<endl;//因为初始化1,所以这里要剪掉1  
		}
	}
	return 0;
}





#include 
#include 
#include 
#include 
using namespace std;
map<string,map<string,int>>people;
map<string,int>score;
int n,m,k; 
int main(void) {
cin>>n>>m>>k;
vector<string>names(n);
for(int i=0;i<n;++i) cin>>names[i];
for(int i=0;i<m;++i){
	int num;
	string str;
	cin>>str>>num;
    score[str]=num;
}
for(int i=0;i<k;++i){
	string name,pro,flag;
	cin>>name>>pro>>flag;
	if(flag=="AC") people[name][pro]=score[pro];//敲重点,不管第一维是int还是string,上面那个代码是int
}
for(int i=0;i<n;++i){
	int sum=0;
	for(auto j : people[names[i]]) sum+=j.second;
	cout<<names[i]<<" "<<sum<<endl;
}
return 0;
}

#include 
#include 
#include 
#include 
using namespace std;
map<int, string> row;//记录顺序
map<string, int>check;//记录有无出现
map<string, int>score;
map<string, int >ans;//记录答案
const int N = 1e5 + 10;
int ch[N];
int main(void) {
	int n, m, k, x;
	string str;
	string a, b, c;
	cin >> n >> m >> k;
	for (int i = 1; i <= n; ++i) {
		cin >> row[i];
		check[row[i]] = 1;
	}
	while (m--) {
		cin >> str >> x;
		score[str] = x;
	}
	while (k--) {
		cin >> a >> b >> c;
		if (c == "AC" && score[b] && check[a]) ans[a] = ans[a] + score[b];
	}
	for (int i = 1; i <= n; ++i) {
		cout << row[i] << " " << ans[row[i]] << "\n";
	}
	return 0;
}

think:还是关注auto的用法,map,vector都可以用的,再关注map套map的用法之类的,都是第一次见

第三种做法是添加一个数组来记录输入的字符串,最后循环这个字符串即可

107 饿饿饭饭
#include  
using namespace std;
const int N=1e5+10;
int a[N],c[N];
int n;
typedef long long ll;
#define int long long
ll er(int mid){
	int ans=0;
	for(int i=1;i<=n;++i){
		if(a[i]>mid) ans+=mid;
		else ans+=a[i]; 
	}
	return ans;
}
signed main(void) {
int maxx=0;
ll k;
cin>>n>>k;
ll sum=0;
for(int i=1;i<=n;++i){
	cin>>a[i];
	sum+=a[i];
	if(a[i]>maxx) maxx=a[i];
}
if(sum<k){
	cout<<-1;
	return 0;
}
int l=0,r=maxx+1;//二分好迷啊,
while(l<r){
	int mid=(l+r+1)/2;//mid代表完整打完的有几轮 
	if(er(mid)<=k) l=mid;
	else r=mid-1;
}
//cout<
k-=er(l);
int tot=0,area,ans=0;
for(int i=1;i<=n;++i){
	if(ans==k) {
		area=i;
		break;
	}
	if(a[i]==l+1) ans++;
	if(a[i]>l+1) {
		ans++; 
		c[++tot]=i;	
	}
}
//cout<
for(int i=area;i<=n;++i){
	if(a[i]>l) cout<<i<<" ";
}
for(int i=1;i<=tot;++i){
	cout<<c[i]<<" ";
}
return 0;
}

think:学习一下二分的思想,二分完整的能打几轮

还有就是long long这一点,卡了很久,我也不知道为什么必须要long long

201
#include 
using namespace std;
const int N=1e5+10;
struct node{
	int start;
	int end;
	int valve;
}n[1002];
int f[1002];
int main(void){
	int t,x,y,z;
	cin>>t;
	for(int i=1;i<=t;++i){
		cin>>x>>y>>z;
		n[i].start=x;
		n[i].end=y;
		n[i].valve=z;
	}
	for(int i=1;i<=1000;++i){
		for(int j=1;j<=t;++j){
			if(n[j].end==i) f[i]=max(f[i],f[n[j].start]+n[j].valve);
			else f[i]=max(f[i-1],f[i]);
		}
	}
	cout<<f[1000];
	return 0;
}
202
#include 
using namespace std;
long long ch[102][102],dp[102][102];
const int mod=1e9+7;
int main(void){
	dp[1][1]=1;
	int n;
	cin>>n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j)
		cin>>ch[i][j];
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(i==1&&j==1) continue;
			if(ch[i][j]==0) dp[i][j]=0;
			else dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
//			cout<
		}
//		cout<
	}
	cout<<dp[n][n];
	return 0;
}
203 最大和上升子序列
#include  
using namespace std;
int a[1010],f[1010];
int main(void) {
int n;
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i){
		f[i]=a[i];//记得初始化,以自身结尾的也是一个子序列
	for(int j=1;j<i;++j){
		if(a[j]<a[i]) f[i]=max(f[i],f[j]+a[i]);
	} 
}
int maxx=0;//记得枚举,因为并不知道以哪个结尾的是最大的,刚开始直接cout f[n]导致错了
for(int i=1;i<=n;++i){
	if(f[i]>maxx) maxx=f[i];
}
cout<<maxx;
return 0;
}
205 跳跳
#include 
#include 
#include 
#include 
using namespace std;
set<pair<int,int> >mp;//敲重点!!!set里面放pair
//map >mp;
int ch[510][2];
int gcd(int x,int y){
	return y==0?x:gcd(y,x%y);
}
int main(void) {
int n;
cin>>n;
for(int i=1;i<=n;++i){
	cin>>ch[i][0]>>ch[i][1];
}
for(int i=1;i<=n;++i){
	for(int j=1;j<=n;++j){
		if(i!=j){
			int x=ch[i][0]-ch[j][0];
			int y=ch[i][1]-ch[j][1];
			// mp.insert(pair(x/gcd(x,y),y/gcd(x,y)));
            //mp.insert(make_pair(x/gcd(x,y),y/gcd(x,y)));
			mp.insert({x/gcd(x,y),y/gcd(x,y)});//这几种写法都可以的
		}
	}
}
cout<<2*mp.size();
return 0;
}


reward:因为最后涉及到统计个数,并需要去重,所以想到用set或者map,但是set里面存两个的写法不会,是用pair来存的,

这题的思想就是全部转化为最小的步数,比如2,4可以转成1,2走两次

106 订单编号
#include 
#include 
using namespace std;
set<pair<int,int> >s;
void insert(int l,int r){
	if(l>r) return;//如果前面的比后面的大,就不插入
	else s.insert(make_pair(r,l));
}
int main(void){
int n,x;
cin>>n;
s.insert({2e9,1});//set有排序的功能,然后要对r排序,所以把r放在第一个参数
while(n--){
	cin>>x;
	auto iter=s.lower_bound(make_pair(x,0));//get 新知识,iter是指针类型,前面用auto,反正我用int 编译过不了,而且lower_bound还能这么用的,直接s.lowerbound,找第一个大于等于x的
	if(iter->second<=x){
		cout<<x<<" ";
		insert(iter->second,x-1);//把小的放前面,如果前面的比后面的大,说明不符合了,就不插入
		insert(x+1,iter->first);
		s.erase(iter);//为什么删的是指针呢,我是想把整个pair删掉
	}
	else {
		cout<<iter->second<<" ";
		insert(iter->second+1,iter->first);
		s.erase(iter);
	}
}
return 0;
}

为什么要大的放前面呢,因为lower_bound找的是第一个大于等于的,如果小的放前面,找的区域就是所要的下一个区域了

pair的写法,make_pair或者是{l,r}

206 异或和或
#include 
using namespace std;
int main(void){
int t;
string str1,str2;
cin>>t;
while(t--){
	int sum1=0,sum2=0;
	cin>>str1>>str2;
	int len1=str1.size();
	int len2=str2.size();
	if(len1!=len2) {
		cout<<"NO"<<"\n";
		continue;
	}
	for(int i=0;i<len1;++i){
		if(str1[i]=='1') sum1++;
		if(str2[i]=='1') sum2++;
	}
	if(sum1==0&&sum2==0) cout<<"YES"<<"\n";
	else if(sum1>=1&&sum2>=1) cout<<"YES"<<"\n";
	else cout<<"NO"<<"\n";
}
return 0;
}

发现如果序列中有1个1,那么他就可以变成很多个1,所以如果两个序列中都有1的话,那么就可以相互转化。反之,如果一个序列有1,另一个序列没有1,就不能转化

207 01序列

还需理解理解

#include 
#include 
using namespace std;
#define int long long
const int N=1e6+10;
char s[N];
int cnt[N];
int f[N];
signed main(void){
int k,ans=0;
scanf("%lld",&k);
getchar();
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=len;++i){
	f[i]=f[i-1]+s[i]-'0';//记录前缀和
}
cnt[0]=1;
for(int i=1;i<=len;++i){
	if(f[i]>=k) ans+=cnt[f[i]-k];//答案为前i个中,大小为i-k的子串的个数
	cnt[f[i]]++;//cnt代表前i个中等于f[i]的子串有多少个
}
printf("%lld",ans);

return 0;
}

首先是前缀和,好像010100这样的用前缀和挺常见的,但是想到前缀和还是On2的复杂度,

与暴力找1 两层for循环没什么区别

加一
#include  
#include 
#include 
#include  
#include 
using namespace std;
vector<int>g;
const int N=2e2+10; 
const int mod=1e9+7;
int vis[N],ans[10][N];
int main(void) {
	int n;
	cin>>n;
	for(int i=0;i<=9;++i){
		 g.clear();
		memset(vis,0,sizeof(vis));
		int sum=0;
		g.push_back(i);
		for(int j=1;j<=20;++j){
			int cnt=0;
			for(int k=0;k<g.size();++k){
				if(g[k]!=9) g[k]++;
				else{
					if(vis[k]==0){
						sum++;
						cnt++;//一开始没考虑到导致打表错误导致转移方程写错,因为push之后容器的size就会变大,导致循环会多执行几次
						vis[k]=1;
					}
				}
			}
			while(cnt--){
			g.push_back(0);
			g.push_back(1);
			}
			ans[i][j]=g.size()-sum;
		}
	}
for(int i=0;i<=9;++i){
	for(int j=1;j<=20;++j) cout<<ans[i][j]<<" ";
	cout<<endl;
}
return 0;
}

首先因为没看出来,所以打表找规律,从而来找动态转移方程,不过i等于9时的方程不太好找,纯靠眼去找挺难

#include
#include
#include
using namespace std;
const int N=2e5+5,P=1e9+7;
int dp[10][N];//记录0-9的数字经过j次之后的长度
void init(){
    for(int i=0;i<=9;++i) dp[i][0]=1;
    for(int j=1;j<=200000;++j)
        for(int i=0;i<=9;++i)
            if(i==9) dp[9][j]=(dp[1][j-1]+dp[0][j-1])%P;
            else dp[i][j]=dp[i+1][j-1];
}
void solve(){
    int n,m; scanf("%d %d",&n,&m);
    int ans=0;
    while(n){
    	ans=(ans+dp[n%10][m])%P;
        n/=10;
    }
    printf("%d\n",ans);
}
int main(){
    init();
    int T; scanf("%d",&T); while(T--) solve();
    return 0;
}
302 序列维护
#include 
#include 
using namespace std;
vector<int>G;
int main(void){
int n,x,y;
cin>>n;
string str;
while(n--){
	cin>>str;//字符串读入,遇到空格停下,而且前面不用getchar,不同于getline(应该吧不确定)
	if(str=="insert"){//string类型支持直接等于比较
		cin>>x>>y;
		G.insert(G.begin()+x,y);
	}
	else if(str=="query"){
		cin>>x;
		cout<<G[x-1]<<endl;
	}
	else if(str=="delete"){
		cin>>x;
		G.erase(G.begin()+x-1);//???????删除第几个元素
	}
}
return 0;
}

如果想到用vector就比较简单了,刚开始想队列去了,熟悉一下vector的相关操作,并且字符串的读入以及比较,

整齐数组

#include 
using namespace std;
int a[50];
int gcd(int a,int b){
	if(b==0) return a;
	return gcd(b,a%b);
}
int main(void){
int t,n;
cin>>t;
while(t--){
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>a[i];
	}
	sort(a+1,a+1+n);
	int first=1,ans;
	for(int i=2;i<=n;++i){
		if(first&&a[i]!=a[1]){
			ans=a[i]-a[1];
			first=0;
		}
		else if(a[i]!=a[1]) ans=gcd(ans,a[i]-a[1]);
	}
	if(first==1) printf("-1\n");
	else printf("%d\n",ans);
}
return 0;
}

首先是所有的数都可以化成最小的数,即最后整齐的数一定是输入中的最小数。搞清楚这点之后就可以找她们与最小的数的最大公约数即可

305删删
#include
using namespace std;
int solve(char s[],int n)
{
	int f=0,ans=100000;
	for(char c='a';c<='z';c++)
	{
		int l=0,r=n-1,cnt=0;
		while(l<r)
		{
			if(s[l]==s[r]) l++,r--;
			else if(s[l]==c) l++,cnt++;
			else if(s[r]==c) r--,cnt++;
			else break; 
		}
		if(l>=r) ans=min(ans,cnt),f=1;
	}
	if(f) return ans;
	return -1;
}
const int M=2e5+5;
char s[M];
int main()
{

	int t;
	scanf("%d",&t);
	while(t--)
	{
		int sl;
		scanf("%d",&sl);
		scanf("%s",s);
		printf("%d\n",(solve(s,sl)));
	}
	return 0;
 } 
饿饿饭饭2
#include 
#include 
using namespace std;
const int N=2e5+10;
int ans[N];
int main(void){
int t,n,x;
scanf("%d",&t);
while(t--){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&x);
	while(x%2==0||x%3==0){
		if(x%2==0) x=x/2;
		if(x%3==0) x=x/3;
	}
	ans[i]=x;
	}
	int flag=1;
	sort(ans+1,ans+1+n);
	for(int i=1;i<=n-1;++i){
		if(ans[i]!=ans[i+1]){
			flag=0;
			break;
		}
	}
	if(flag) cout<<"YES"<<'\n';
	else cout<<"NO"<<'\n';
}
return 0;
}

一个数乘2乘3最后成为相等的,那么把他化成 x = 2 a ∗ 3 b ∗ h h h x=2^a*3^b*hhh x=2a3bhhh(hhh中不含有2的因子,不含有3的因子) 所以两个数如果最后能化成一样的话,那么他们的hhh肯定是一样的,明白这一点后就好实现了,把所有数的hhh找出来比较是否相等即可

401子串分支和

1.很普通的想法,比如是 a b a b c ababc ababc

a b a b c

ab ba ab c

aba bab abc

abab babc

ababc

但是子串长度为1e6 这样两层for循环肯定超时

2.考虑a所在的子串有多少个,b所在的子串有多少个,c所在的子串有多少个,三者相加即可

那a所在的子串有多少个呢,直接算不好算吧,考虑所有的子串减去a不在的子串就是a所在的子串

#include 
#include 
using namespace std;
const int N=1e6+10;
char str[N];
int main(void){
scanf("%s",str+1);
int len=strlen(str+1);//!!!!!!!!!!!!!!!必须要str+1哦,因为上面读入的时候是str+1
long long ans=0;
for(int i=97;i<=97+25;++i){
	char s=i;
	long long flag=0;
	long long sum=0;
	for(int j=1;j<=len;++j){
		if(str[j]==s) {
		sum=sum+1LL*(j-flag)*(j-flag-1)/2;//!!!!!!!!
		flag=j;
		}
	}
	sum=sum+1LL*(len+1-flag)*(len-flag)//2;!!!!!!!!!!大数相乘爆int了的
	ans=ans+1LL*len*(len+1)/2-sum;//!!!!!!!!!
}
    //实验了一下,发现只要把len的类型改为long long下面即可不用加1LL 或者直接#define int long long
    //还有就是1LL变成(long long) 后面无需加括号,如果把后面两个相乘再加上括号就错了
cout<<ans;
return 0;
}

402
#include 
#include 
using namespace std;
const int N=1e6+10;
set<pair<int,int> >s1,s2;
bool jia[N],kou[N];
int main(void){
int n,op,w,t;
long long sum=0;
cin>>n;
while(n--){
	cin>>op;
	if(op==1){
		cin>>w>>t;
		if(jia[w]||kou[t]) continue;
		s1.insert(make_pair(w,t));//以价格为关键字
		s2.insert((make_pair(t,w)));
		jia[w]=true;
		kou[t]=true;
	}
	else if(op==2){
		 set<pair<int,int>>::iterator iter;
		 iter=s1.begin();//这里其实不用这么麻烦的,但也是一种方法,见下文
		int x=iter->first;
		int y=iter->second;
		s1.erase(iter);
		s2.erase(make_pair(y,x));
		jia[x]=false;
		kou[y]=false;
	}
	else if(op==3){
		set<pair<int,int>>::iterator iter;
		 iter=s2.begin();
		int x=iter->first;
		int y=iter->second;
		s2.erase(iter);
		s1.erase(make_pair(y,x));
		jia[y]=false;
		kou[x]=false;
	}
}
set<pair<int,int>>::iterator iter;
for(iter=s1.begin();iter!=s1.end();++iter){
	sum=sum+iter->first;
}
cout<<sum;
return 0;
}


#include 
#include 
using namespace std;
const int N=1e6+10;
set<int>w1;
set<int>t1;
int w_t[N];//价格对应的口感
int t_w[N];//口感对应的价格,因为w,t有范围,可以用数组存
int main(void){
int n,op,w,t;
int sum=0;
cin>>n;
while(n--){
	cin>>op;
	if(op==1){
		cin>>w>>t;
		if(w_t[w]||t_w[t]) continue;
		w_t[w]=t;
		t_w[t]=w;
		w1.insert(w);
		t1.insert(t);
	}
	else if(op==2){
		w=*w1.begin();
		w1.erase(w1.begin());//这样不用迭代
		t=w_t[w];
		t1.erase(t);
		w_t[w]=0;
		t_w[t]=0;
	}
	else if(op==3){
		t=*t1.begin();
		t1.erase(t1.begin());
		w=t_w[t];
		w1.erase(w);
		w_t[w]=0;
		t_w[t]=0;
	}
}
for(auto i:w1){
	sum+=i;
}
cout<<sum;
return 0;
}




#include 
#include 
using namespace std;
const int N=1e5+10;
map<int,int>w_t;
map<int,int>t_w;//脑残加了个参数
int main(void){
int n,op,w,t,sum=0;
cin>>n;
while(n--){
	cin>>op;
	if(op==1){
		cin>>w>>t;
		if(w_t.count(w)||t_w.count(t)) continue;//这里如果改成if(w_t[w]||t_w[t])就有问题
        //map中会自动生成一个0,然后会对程序哪里有影响呢,别用那种就行了,记得找某个元素用count就行
		w_t[w]=t;
		t_w[t]=w;
	}
	else if(op==2){
		t_w.erase(w_t.begin()->second);
		w_t.erase(w_t.begin());
	}
	else if(op==3){
		w_t.erase(t_w.begin()->second);//上下顺序不能换哦
		t_w.erase(t_w.begin());
	}
}
	for(auto i:w_t){
		sum=sum+i.first;
		}
cout<<sum;
return 0;
}



#include
using namespace std;
set < pair<int ,int > > a,b;
int n,op,w,t;
long long ans;
int main(){
	scanf("%d",&n);
	while(n--){
		scanf("%d",&op);
		if(op==1){
			scanf("%d%d",&w,&t);
			auto itr=a.lower_bound(make_pair(w,0));
			if(itr!=a.end()&&itr->first==w)continue;
			itr =b.lower_bound(make_pair(t,0));
			if(itr!=b.end()&&itr->first==t)continue;
			a.insert(make_pair(w,t));
			b.insert(make_pair(t,w));
		}
		if(op==2){
			auto it=a.begin();//省去了迭代器,直接auto
			int x=it->first,y=it->second;
			//auto it1=b.find(make_pair(y,x));
			a.erase(make_pair(x,y));b.erase(make_pair(y,x));
		}
		if(op==3){
			auto it2=b.begin();
			int x1=it2->first,y1=it2->second;
			//auto it3=a.find(make_pair(y1,x1));
			b.erase(make_pair(x1,y1));a.erase(make_pair(y1,x1));
		}
	}
	for(auto itr=a.begin();itr!=a.end();itr++){
		//printf("%d\n",itr->first);
		ans+=itr->first;
	}
	printf("%lld",ans);
	return 0;
}

展示一下map寻找有无值方法,发现size会变多,从本来的0变成了100

锦标赛(思维题哇)
#include 
using namespace std;
const int N=1e5+10;
int a[N];
int main(void){
int n,k,sum=1;
cin>>n>>k;
for(int i=1;i<=n;++i) cin>>a[i];
sort(a+1,a+1+n);
for(int i=n;i>=2;--i){
	if(a[i]-a[i-1]>k) break;
	sum++;
}
cout<<sum;
return 0;
}

排一下序,从后往前找,找到大于k的就退出了

404 可重排列

(简单题,只要会用next_permutation)

#include 
using namespace std;
const int N=1e5+10;
int a[N];
int main(void){
int n,x;
cin>>n;
int k=0;
for(int i=1;i<=n;++i){
	cin>>x;
	for(int j=1;j<=x;++j){
		a[k++]=i;
	}
}
do{
	for(int i=0;i<k;++i) cout<<a[i]<<" ";
	cout<<"\n";
}while(next_permutation(a,a+k));
return 0;
}

你可能感兴趣的:(算法入门,算法,c++,图论,动态规划)