week 2

  • 跳跳

求两个位置之间的gcd,时间复杂度过高;

简化:dx与dy之间先求最大公因数【把一步最简化的过程】+ 去重【set】

#include<bits/stdc++.h>
using namespace std;
set< pair<long,long> >s;
const int maxn=1e5;
long x[maxn];
long y[maxn];
int main()
{
	int n;cin>>n;
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		cin>>x[i]>>y[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			long dx=abs(x[i]-x[j]);
			long dy=abs(y[i]-y[j]);
			long k=__gcd(dx,dy);
			s.insert(make_pair(dx/k,dy/k));
		}
	}
	cout<<s.size()*2;
	return 0;
}
int gcd(int x,int y)
{
    return b?gcd(b,a%b):a;
}
  • 异或和或

    留意细节,理清思路

    • 0 1-1 1、1 0- 1 1、0 0- 0 0、1 1-1 0、1 0- 0 1【两步变换】
    • 1变成0 条件 存在 1 1或者0 1
    • 0变成1 条件存在1 1 或者1 0
    #include<iostream>
    using namespace std;
    int main()
    {
    	int t;cin>>t;
    	while(t--)
    	{
    		string s;
    		string t;
    		cin>>s>>t;
    		int ls=s.size();
    		int lt=t.size();
    		int s00=0,s01=0,s10=0,s11=0;
    		if(ls!=lt) cout<<"NO";
    		else{
    			for(int i=0;i<ls;i++)
    			{
    				if(s[i]=='1'&&t[i]=='1')
    				{
    					s11++;
    				}
    				if(s[i]=='1'&&t[i]=='0')
    				{
    					s10++;
    				}
    				if(s[i]=='0'&&t[i]=='0')
    				{
    					s00++;
    				}
    				if(s[i]=='0'&&t[i]=='1')
    				{
    					s01++;
    				}
    			}
    			if((s10>0&&(s11==0&&s01==0))||(s01>0&&(s11==0&&s10==0))) cout<<"NO";
    			else cout<<"YES";
    		}
    		cout<<endl;
    	}
    }
    
  • 01序列

    • 注意分类:k==0需要单独讨论
    • k!=0的时候根据前导0与后置0求答案【仔细分析,数学问题】
    • 子串得是相连的!!不是2^n
    • 求前导0 与 后置0 方法
      • 用vector储存1的位置
      • 双指针
    #include<bits/stdc++.h>
    using namespace std;
    vector<long long>v;
    int main()
    {
    	long long k;
    	cin>>k;
    	string s;
    	cin>>s;
    	v.push_back(0);
    	for(long long i=0;i<s.size();i++)
    	{
    		if(s[i]=='1')
    		v.push_back(i+1);
    	}
    	v.push_back(s.size()+1);
    	long long sum=0;
    	long long l=v.size();
    	if(k<v.size()&&k!=0)
    	{
    		for(long long i=1;i<l-k;i++)
    	   {
    		long long x=v[i]-v[i-1];
    		long long y=v[i+k]-v[i+k-1];
    		sum+=x*y;
    	   }
    	}
    	else if(k==0)
    	{
    		for(long long i=1;i<l-k;i++)
    		{
    			long long x=v[i]-v[i-1]-1;
    			sum+=x*(x+1)/2;
    		}
    	}
    	else if(k>v.size()) sum=0;
    	cout<<sum;
    	return 0;
    }
    
  • 加一:!

    • 又被cin 和cout 卡了!
    • 利用动态规划:f[i] [j]表示第i次操作时该数位为j的个数
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e9+7;
const int x=200050;
long long f[x][10]={0};
int main()
{
	int t;
	scanf("%d",&t);
    for(int i=0;i<=9;i++) f[0][i]=1;
    for(int i=1;i<=x;i++)
    {
    	for(int j=1;j<=9;j++) f[i][j-1]=f[i-1][j];
    	f[i][9]=(f[i-1][1]+f[i-1][0])%maxn;
	}
	while(t--)
	{
		char a[20];
		int m;
		long long ans=0;
		scanf("%s %d",&a,&m);
		int l=strlen(a);
        //统计所有数的个数
		for(int i=0;i<l;i++)
		{
			ans+=f[m][a[i]-'0'];
			ans%=maxn;
		}
		printf("%d\n",ans);
	}
	return 0;
}
  • 整齐的数组:求一组数的最大公因数:ans记录此时的最大公因数;思想就是所有数的公因数一定是某两个数的公因数
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6;

int main()
{
	int t;cin>>t;
	int a[100]={0};
	while(t--)
	{
		int n;
		cin>>n;
		
		int flag=0;
		for(int i=1;i<=n;i++) {
			cin>>a[i];
		}
		for(int i=1;i<=n;i++)
		{
			if(a[i]!=a[1])
			{
				flag=1;
				break;
				
			}
		}
		sort(a+1,a+1+n);
		int ans=0;
		if(flag==0) cout<<"-1"<<endl;
		else
		{
			//求数组中所有数的公因数
            for(int i=2;i<=n;i++)
			{
				if(a[i]!=a[1])
				{
					ans=__gcd(ans,a[i]-a[1]);
				}
			}
			cout<<ans<<endl;
		}
	}
	return 0;
}
  • 网格判断
    • 分别罗列 行和列
    • 简单的模拟
#include<iostream>
using namespace std;
int main()
{
	int n;
	cin>>n;
	int a[30][30];
	for(int i=1;i<=n;i++)
	{
		int s1=0,s0=0;
		for(int j=1;j<=n;j++)
		{
			char x;
			cin>>x;
			if(x=='W') 
			{
				a[i][j]=1;
				s1++;
			}
			else {
				a[i][j]=0;
				s0++;
			}
		}
		if(s1!=s0)
		{
			cout<<"0";
			return 0;
		}
	}
	for(int j=1;j<=n;j++)
	{
		int s1=0;int s0=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i][j]==1) s1++;
			else s0++;
		}
		if(s1!=s0)
		{
			cout<<"0";
			return 0;
		}
	}
	int x=0,s=0;
	for(int i=1;i<=n;i++)
	{
		x=0;s=0;
		for(int j=1;j<=n;j++)
		{
			if(a[i][j]!=x)
			{
				x=a[i][j];
				s=1;
			}
			else {
				s++;
			}
			if(s>=3)
			{
				cout<<"0";
				return 0;
			}
		}
	}
	for(int j=1;j<=n;j++)
	{
		x=0;
		s=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i][j]!=x)
			{
				x=a[i][j];
				s=1;
			}
			else {
				s++;
			}
			if(s>=3)
			{
				cout<<"0";
				return 0;
			}
		}
	}
	cout<<"1";
	return 0;
}
  • 出栈序列判断
    • stack的应用
    • 遇到相同的数就pop
    • 不相同就push
#include<iostream>
#include<stack>
using namespace std;
const int maxn=1e6;
stack<int>s;
int a[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	int k=1;
	for(int i=1;i<=n;i++)
	{
		s.push(i);
		printf("push %d\n",i);
		while(!s.empty()&&s.top()==a[k])
		{
			s.pop();
			printf("pop\n");
			k++;
		}
	}
	return 0;
}
  • 序列维护
    • 可以手写链表
    • 也可以用stl中的list
#include<bits/stdc++.h>
using namespace std;

int main()
{
	int m;cin>>m;
	list<int>q;
	while(m--)
	{
		string b;
		cin>>b;
		//在某个位置插入
		if(b[0]=='i')
		{
			int x,y;
			cin>>x>>y;
			list<int>::iterator it=q.begin();
			if(x==0) q.insert(it,y);
			else {
				while(x)
				{
					it++;
					x--;
				}
				q.insert(it,y);
			}
		}
		//删除
		else if(b[0]=='d')
		{
			int x;cin>>x;
			list<int>::iterator it=q.begin();
			while(x-1)
			{
				it++;
				x--;
			}
			q.erase(it);
		}
		//查询
		else
		{
			int x;cin>>x;
			list<int>::iterator it=q.begin();
			while(x-1)
				{
					it++;
					x--;
				}
			cout<<*(it)<<endl;
		}
	}
	return 0;
}
  • 饿饿饭饭
    • 一开始的思路是最小公倍数是2m+3k 时间复杂度过大
    • 通过数学公式变化 可以变成除以最大公因数能否变成2m+3k 形式
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;cin>>n;
		int a[100005];
		for(int i=1;i<=n;i++) cin>>a[i];
		int ans=a[1];
		for(int i=1;i<=n;i++)
		{
			ans=(ans,__gcd(ans,a[i]));
		}
		int flag=0;
		for(int i=1;i<=n;i++)
		{
			int m=a[i]/ans;
			while(m%2==0)
			{
				m/=2;
			}
			while(m%3==0)
			{
				m/=3;
			}
			if(m!=1) {
				flag=1;
				break;
			}
		}
		if(flag==0) cout<<"YES";
		else cout<<"NO";
		cout<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值