8.16-8.19学习笔记(三场比赛)

2019年我能变强组队训练赛第四场8.16

纪念一下这个差点被hack的比赛

G题

在这里插入图片描述
题目比较水,主要是理解,用了排序。其他就是按照题目敲

#include<bits/stdc++.h>
using namespace std;
struct node{
	int a,t,v;
}s[11000];
bool cmp(node x,node y){
	return x.a>y.a;
}
int main(){
	int n;
	scanf("%d",&n);
	double s1=0;
	int v1=0;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&s[i].a,&s[i].t);
		s[i].v=s[i].a*s[i].t;
		s1+=v1*s[i].t+0.5*s[i].a*s[i].t*s[i].t;
		v1+=s[i].v;
	} 
	sort(s+1,s+n+1,cmp);
	double s2=0;
	int v2=0;
	for(int i=1;i<=n;i++){
		s2+=v2*s[i].t+0.5*s[i].a*s[i].t*s[i].t;
		v2+=s[i].a*s[i].t;
	}
	double ans=s2-s1;
	printf("%.1lf\n",ans);
	return 0;
} 

K题

在这里插入图片描述
题目比较好理解-还原原序列;
就因为这个差点领了盒饭。
画个图,思路就有了。
举个例子!
将第一维的最大上升序列的下标记在第二维(用于记录原来的位置):
第一维x: 1 1 2 3 3 2 1 1
第二维num:1 2 3 4 5 6 7 8
按第一维排序:
x: 1 1 1 1 2 2 3 3
num:1 2 7 8 3 6 4 5
第三维:8 7 6 5 4 3 2 1(倒序填入对应的x)
为了将x变回原本的位置
将整个结构体按num再次排序
返回原本的顺序
x:1 1 2 3 3 2 1 1
num:1 2 3 4 5 6 7 8
r: 8 7 4 2 1 3 6 5

输出的第三维就是答案

#include<bits/stdc++.h> 
using namespace std;
struct P    
{
    int x,num,r;
};
bool cmp1(P a,P b)  //第一次比较
{
    if(a.x!=b.x)
        return a.x<b.x;
    return a.num<b.num;

}
bool cmp2(P a,P b)
{
    return a.num<b.num;
}
int main()
{
    struct P s[100005]= {0};
    int n,i,x,t;
    scanf("%d",&n);
    for(i=1; i<=n; i++)
    {
        scanf("%d",&t);
        s[i].num=i;  
        s[i].x=t;    
    }
    sort(s+1,s+1+n,cmp1); 
    int k=n;
    for(i=1; i<=n; i++)    
    {
        s[i].r=k;
        k--;
    }
    sort(s+1,s+1+n,cmp2);  
    for(i=1;i<n;i++)printf("%d ",s[i].r);
    printf("%d\n",s[n].r);
    return 0;
}

J题

博弈论题目
在这里插入图片描述
本题的突破口在于1。分为以下几种情况讨论:

  1. 全是1的情况 如果n≡0(mod3),A是必输的,否则是必胜的。
  2. 只有一个不是1的情况,那么A是必胜的。因为如果n≡0(mod3),那么将不是1的那堆取成1,这样就相当于变成了n≡1(mod3)的必胜态。否则就按照情况1的方式取。
  3. 有两个不是1的情况:
    首先我们可以知道,假如只有两堆,并且这两堆都不是1,那么A是必输的。如果加了m堆1,那么若m≡0(mod3),那么A必输(因为B,C总能取成n≡0(mod3)的状态)。如果不是,并且存在至少一堆是2,A必胜(余1将不是2的那一堆取成1,余2将不是2的那堆取完)。
  4. 对于大于等于3的情况,另外两个人总可以转为2的必败态。A是必败的。

对于博弈论来说,求特殊值和求出各种情况格外重要

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
  int n;cin>>n;
  int cnt1=0,cnt2=0;
  for(int i=1;i<=n;i++){
    int x;
	cin>>x;
    if(x==1)++cnt1;
    else if(x==2)++cnt2;
  }
  if(cnt1==n-1)
  cout<<"Win"<<endl;
  else if(cnt1==n)
  {
  	if(cnt1%3==0)
  	cout<<"Lose"<<endl;
	else
	cout<<"Win"<<endl; 
  }
  else if(cnt1==n-2)
  {
  	if((cnt2&&cnt1%3))
  	cout<<"Win"<<endl;
  	else cout<<"Lose"<<endl;
  }
  else cout<<"Lose"<<endl;
return 0; 
}

A题

一直在试图搓出来的dp
在这里插入图片描述
尝试download 别人的思路
题目的意思是某人想按照输入长度为k的这个顺序看演唱会,输入长度为n的这个是所有的顺序,然后A-Z代表的是看演唱会之前需要在家至少待几天。
就可以考虑到dp[i][j]=dp[i+1][j]+dp[i+str1[i]-‘A’+1][j+1]

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
char str1[150];
char str2[100005];
int valu[30];
int dp[100005][105];	
int main()
{
	int n,k;
	scanf("%d%d",&k,&n);
	for(int i=0;i<26;i++)
		scanf("%d",&valu[i]); 
	scanf("%s",str1+1);//k  需要比较的串 
	scanf("%s",str2+1);//n   母串 
	for(int i=n;i>=1;i--)//枚举最大的那个串 
	{
		for(int j=k;j>=1;j--)//枚举比较的串 
		{
			dp[i][j]=dp[i+1][j];
			if(j==k && str1[j]==str2[i])//如果当前是最后一个 而且等于上边的那个 
				dp[i][j]=(dp[i][j]+1)%mod;	
			else if(i+valu[str2[i]-'A']+1<=n && str2[i]==str1[j])
				dp[i][j]=(dp[i][j]+dp[i+valu[str2[i]-'A']+1][j+1])%mod;
		}
	}
	printf("%d\n",dp[1][1]);
	return 0;
}

2019牛客暑期多校训练营第10场 8.17

H题

在这里插入图片描述
这一场最水的题目

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        int a[7] = { 0 },c[7]={0};
        int b[7][7] = { 0 };
        int k,j,flag=0,ans=0,bns=0;
        for (int i = 0; i < 5; i++)
        {
            cin >> k >> j;
            b[j][k]=b[k][j] = 1;
            a[k]++;
            c[k]++;
            c[j]++;
            a[j]++;
            if (a[j] == 3)
                flag = j;
            if (a[k] == 3)
                flag = k;
        }
        sort(a, a + 7);
        if (a[1] == 1 && a[2] == 1 && a[3] == 2 && a[4] == 2 && a[5] == 2 && a[6] == 2)
        {
            cout << "n-hexane" << endl;
            continue;
        }
        if (a[1] == 1 && a[2] == 1 && a[3] == 1 && a[4] == 2 && a[5] == 2 && a[6] == 3)
        {
            for (int i = 1; i <= 6; i++)
            {
                if (b[flag][i] == 1)
                {
                    if (c[i] == 1)
                        ans++;
                    if(c[i]==2)
                    bns++;
                }
            }
            if(ans==2&&bns==1)
            cout << "2-methylpentane" << endl;
            else cout << "3-methylpentane" << endl;
            continue;
        }
        if (a[1] == 1 && a[2] == 1 && a[3] == 1 && a[4] == 1 && a[5] == 3 && a[6] == 3)
        {
            cout << "2,3-dimethylbutane" << endl;
            continue;
        }
        if (a[1] == 1 && a[2] == 1 && a[3] == 1 && a[4] == 1 && a[5] == 2 && a[6] == 4)
        {
            cout << "2,2-dimethylbutane" << endl;
            continue;
        }
    }
    return 0;
}
/*2
1 2
2 3
3 4
4 5
5 6
1 4
2 3
3 4
4 5
5 6
*/

B题

在这里插入图片描述
利用递归的性质
!!注意,数据很大,所以循环开到60!!

#include <bits/stdc++.h>
using namespace std;
long long len[505];
string x="COFFEE";string y="CHICKEN";
char f(int a,long long b){
        if(a==1) return x[b-1];
        if(a==2) return y[b-1];
        else if(b<=len[a-2]) return f(a-2,b);
        else return f((a-1),b-len[a-2]);//S(n-2):S(n-1) 如果处于的位置大于len【a-2】则该位置在S(n-1)之中
    }
int main(){
    len[1]=6;len[2]=7;
    for(int i=3;i<=60;i++){
        len[i]=len[i-1]+len[i-2];
    }
    int t;cin>>t;
    while(t--){
        int x;long long y;
        cin>>x>>y;
        if(x>60) x=60;
        for(long long j=y;j<y+10;j++){
            if(j>len[x]) break;//字符超限
            cout<<f(x,j);
        }
        cout<<endl;
    }
    return 0;
}

2019年我能变强组队训练赛第五场 8.18

J题

水题 排序
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
struct node{
	string s;
	int m;
}a[10050];
bool cmp(node x,node y){
	return x.m>y.m;
}
int main(){
	int n,d,k;
	cin>>n>>d>>k;
	for(int i=1;i<=n;i++) cin>>a[i].s>>a[i].m;
	sort(a+1,a+n+1,cmp);
	int tot=0,ans=0;
	for(int i=1;i<=k;i++){
		tot+=a[i].m;
		ans++;
		if(tot>=d){
			break;
		}
	}
	if(tot>=d) cout<<ans<<endl;
	else cout<<"impossible"<<endl;
	return 0;
} 

C题

在这里插入图片描述
正向建图

#include<bits/stdc++.h>
using namespace std;
int a[1050][1050];
map<string,int>q;
int main(){
	memset(a,0,sizeof(a));
	int n,m;
	string s1,s,s2;
	int t=0;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int x=0,y=0;
		cin>>s;
		if(!q[s]) q[s]=++t;
		x=q[s];
		cin>>s;
		cin>>s;
		cin>>s;
		cin>>s;
		if(!q[s]) q[s]=++t;
		y=q[s];
		a[x][y]=1;//表示有边
	}
	for(int k=1;k<=t;k++)
	for(int i=1;i<=t;i++)
	for(int j=1;j<=t;j++)
	a[i][j]=a[i][j]||(a[i][k]&&a[k][j]);//建图
	for(int i=1;i<=m;i++){
		int u=0,v=0;
		cin>>s;
		u=q[s];
		cin>>s;
		cin>>s;
		cin>>s;
		cin>>s;
		v=q[s];
		if(a[u][v]) cout<<"Fact\n";
		else if(a[v][u]) cout<<"Alternative Fact\n";
		else cout<<"Pants on Fire\n";
	}
	return 0;
}

F题

在这里插入图片描述
题意:

在点阵上,给出 N 个点的坐标(全部都是在格点上),将它们按顺序连接可以构成一个多边形,求该多边形内包含的格点的数目。
首先,根据皮克定理 S=a+ b 2 \frac{b}{2} 2b−1,其中 S 是多边形面积,a 是多边形内部格点数目,b 是多边形边界上的格点数目。
那么,我们只要求出 S 和 b,就很好求得 a 了:
1、对于两端点 ( x 1 , y 1 ) , ( x 2 , y 2 ) \left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right) (x1,y1),(x2,y2) 都再格点上的一条线段,该线段上的格点数目为 gcd ⁡ ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) \operatorname{gcd}\left(\left|x_{1}-x_{2}\right|,\left|y_{1}-y_{2}\right|\right) gcd(x1x2,y1y2)。这很好理解,对于横坐标差值和纵坐标差值求得的最大公因数 g,相当于将横坐标差值分成 g 份,由于是整除,因此显然每份的左右端点都是整数,对于纵坐标也是同样的道理,由于是最大公因数,所以不可能再分更多份,因此 gcd(|x1−x2|,|y1−y2|) 即求得两端点间最多能分成多少段由格点分割的线段,再加上 1 即整条线段上的格点数目。
2、对于格点按顺序给出的多边形,设 P 0 = P n + 1 P_{0}=P_{n+1} P0=Pn+1 且 O 为原点,则面积为 1 2 ∑ i = 0 n ( O P i → × O P i + 1 → ) \frac{1}{2} \sum_{i=0}^{n}(\overrightarrow{O P_{i}} \times \overrightarrow{O P_{i+1}}) 21i=0n(OPi ×OPi+1 )。这个画个图模拟一下也非常容易理解。
皮克定理,小本本记下来

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{
	ll x,y;
}a[100050];
int main(){
	int n;
	ll s=0,b=0;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
	for(int i=1;i<=n;i++){
		int t=0;
		if(i+1>n) t=1;else t=i+1;
		s+=a[i].x*a[t].y-a[i].y*a[t].x;
		//s=os1^os2叉乘
		b+=__gcd(abs(a[i].x-a[t].x),abs(a[i].y-a[t].y))+1;
	}
	b=b-n;//重复计算了两端点 
	cout<<(abs(s)-b+2)/2<<endl;
	//s=a+b/2-1,s面积,b边界上点数,a多边形内点数 
	return 0;
}

持续学习ing

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值