福建省第八届程序设计大赛专题

26 篇文章 0 订阅
19 篇文章 0 订阅

A:鸡兔同笼问题。小学生都会。。。

 

B:判断两三角形是否相交或包含或相离。那么判断一个点是否在一个多边形内的算法有多种可以看角和是不是360或者用这个点延伸一条射线看他与多边形的交点是否为奇数就行了。

 

#include <stdio.h>
#include <cstring>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx =1e3+10,mod = 1e9+7;
int n,m;
double a[3][2],b[3][2];
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
        for(int i=0;i<3;i++) scanf("%lf%lf",&a[i][0],&a[i][1]);
        for(int i=0;i<3;i++) scanf("%lf%lf",&b[i][0],&b[i][1]);
        int inter = 0,c1 = 0,c2 = 0;
        for(int j=0;j<3;j++){
            int cnt = 0;
            for(int i=0;i<3;i++){
                int to = (i+1)%3;
                if(a[i][0]==a[to][0]) continue;
                if(b[j][0]<min(a[i][0],a[to][0])) continue;
                if(b[j][0]>max(a[i][0],a[to][0])) continue;
                double k = (a[i][1]-a[to][1])/(a[i][0]-a[to][0]);
                double y = k*(b[j][0]-a[i][0])+a[i][1];
                if(y==b[j][1]) inter = 1;
                if(y<b[j][1])  cnt++;
           }
           c1 += cnt&1;
        }
        for(int j=0;j<3;j++){
            int cnt = 0;
            for(int i=0;i<3;i++){
                int to = (i+1)%3;
                if(b[i][0]==b[to][0]) continue;
                if(a[j][0]<min(b[i][0],b[to][0])) continue;
                if(a[j][0]>max(b[i][0],b[to][0])) continue;
                double k = (b[i][1]-b[to][1])/(b[i][0]-b[to][0]);
                double y = k*(a[j][0]-b[i][0])+b[i][1];
                if(y==a[j][1]) inter = 1;
                if(y<a[j][1]) cnt++;
           }
           c2 += cnt&1;
        }
        if(inter) puts("intersect");
        else if(c1==3||c2==3) puts("contain");
        else if(c1||c2) puts("intersect");
        else puts("disjoint");
	}
    return 0;
}

 

 

C:没去看好像有点麻烦的样子。。待更新

 

D:这题我感觉后台数据很有问题,反正这题毛病很多,建议不要去做,正常KMP过不了(也不能光KMP),有点错的KMP才AC我也是醉了。(可以思考但是你想能AC的代码可能过不了)

 

E:待更新。。。

 

F:用懒人思想暴力求解。数据不坑肯定能过,还跟用树状数组的差不多。

 

#include <stdio.h>
#include <cstring>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx =3e5+10;
const ll mod = 1e9+7;
int n,m,fa[mx];
ll val[mx][2];
ll query(int x,int k){
    if(x==1) return (val[1][0]-k*val[1][1])%mod;
    ll ans = (val[x][0]-k*val[x][1])%mod;
    return (ans+query(fa[x],k+1))%mod;
}
int main(){
	int t;
	scanf("%d",&t);
	fa[1] = 1;
	while(t--){
	    scanf("%d",&n);
	    for(int i=1;i<=n;i++) val[i][0] = val[i][1] = 0;
	    for(int i=2;i<=n;i++) scanf("%d",fa+i);
	    scanf("%d",&m);
	    while(m--){
            ll x,k;
            int u,v;
            scanf("%d%d",&u,&v);
            if(u==1){
                scanf("%I64d%I64d",&x,&k);
                val[v][0] = (val[v][0]+x)%mod;
                val[v][1] = (val[v][1]+k)%mod;
            }else{
                printf("%I64d\n",(query(v,0)+mod)%mod);
            }
	    }
	    //system("pause");
	}
    return 0;
}

 

G:大数。不明白为什么要出两题大数坑人,也是醉了。这里先要求出n!,然后答案是∑(n!)/i,i是1-n,那么这里就一共要用到乘法,除法,和加法三个大数运算,性质差不多,用以求得的n!去逐个操作然后累加就行了。

 

 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mx = 1e4+10,mod = 1e4;
int ans[mx],len,n,ret[mx],lens,now[mx];
void add()
{
	int c = 0;
	for(int i=0;i<len;i++){
		ret[i] += c + now[i];
		c = ret[i]/mod;
		ret[i] %= mod;
	}
	if(c) ret[len] += c,lens = len+1;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		ans[0] = len = 1; 
		for(int i=1;i<=n;i++){
			int c= 0;
			for(int j=0;j<len;j++){
				ans[j] = c + ans[j]*i;
				c = ans[j]/mod;
				ans[j] %= mod;
			}
			if(c) ans[len++] = c;
		}
		lens = len;
		memset(ret,0,sizeof(ret));
		for(int i=1;i<=n;i++){
			for(int j=len-1,c=0;j>=0;j--){
				now[j] = (c*mod+ans[j])/i;
				c = (c*mod+ans[j])%i;
			}
			add();	
		}
		printf("%d",ret[lens-1]);
		for(int i=lens-2;i>=0;i--) printf("%04d",ret[i]);
		puts(".0");
    } 
	return 0;
}

 

 

 

 

 

H:待更新

I:求其它字符串的后缀包含自己且val小等自己的有多少。为了简单一点先把所以字符串都反过来看前缀。然后根据字符串大小排序。接下来就看排序后的i这个位置能延伸多长了。然后暴力看有多少val是小等它的。这里b数组是因为字符串可能完全相同所以i的位置可能后面还有前缀相同的,所以要维护一下。求某一个字符串的左右界可以用hash,但是这里介绍更简单易懂的就是直接保存i和i-1的前缀长度,然后就可以递推下去了。

 

#include <stdio.h>
#include <cstring>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx =1e3+10,mod = 1e9+7;
int n,m,a[mx],lon[mx],b[mx];
struct node{
    char str[mx];
    int val,pos;
    bool operator < (node A)const{
         return strcmp(str,A.str)<0;
    }
}s[mx];
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
	    scanf("%d",&n);
	    for(int i=1;i<=n;i++){
            scanf("%s%d",&s[i].str,&s[i].val);
            reverse(s[i].str,s[i].str+strlen(s[i].str));
            s[i].pos = i;
	    }
	    sort(s+1,s+1+n);
	    a[s[1].pos] = b[1] = 1;
 	    for(int i=2;i<=n;i++){
            if(!strcmp(s[i].str,s[i-1].str)) b[i] = b[i-1];
            else b[i] = i;
            a[s[i].pos] = i;
	    }
	    for(int i=2;i<=n;i++){
            lon[i] = 0;
            int len = min(strlen(s[i].str),strlen(s[i-1].str));
            for(int j=0;j<len;j++)
            if(s[i].str[j]==s[i-1].str[j]) lon[i]++;
            else break;
	    }
	    scanf("%d",&m);
	    int x,y,z;
	    while(m--){
            scanf("%d%d",&x,&y);
            if(x==1){
                scanf("%d",&z);
                s[a[y]].val = z;
            }else{
                int len = strlen(s[a[y]].str),ans=0,po = a[y];
                if(s[po].val>=s[b[po]].val) ans++;
                for(int i=b[po]+1;i<=n&&lon[i]>=len;i++)
                    if(s[po].val>=s[i].val) ans++;
                printf("%d\n",ans);
            }
	    }
	}
    return 0;
}


J:通过贪心可得当a[i]>a[i-1]时,m可更新为 m/a[i-1]*a[i] + m%a[i-1],然后就转化成了大数问题,这里不懂val【0】为什么不用考虑是否会溢出我们的押位(可能是数据问题)。

 

 

#include <stdio.h>
#include <cstring>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx =2e3+10,mod = 1e9,MOD = 1e9+7;
int n,m,a[mx];
ll ans[mx*5],now[mx*5];
int main(){
    int t,cas=1;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        ans[0] = m;
        int len = 1;
        //ll *x = ans,*y = now;
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        for(int i=2;i<=n;i++){
            if(a[i]>a[i-1]){// m = m / a[i-1] * a[i] + m % a[i-1]
                ll c=0;
                for(int j=len-1;j>=0;j--){
                    ll p = c*1e9 + ans[j];
                    now[j] = p/a[i-1];
                    c = p%a[i-1];
                }
                int val = c;
                c = 0;
                for(int j=0;j<len;j++){
                    ll p = c + now[j]*a[i];
                    ans[j] = p%mod;
                    c = p/mod;
                }
                if(c) ans[len++] = c;
                ans[len] = 0, ans[0] += val;
            }
        }
        ll sum = 0;
        for(int i=len-1;i>=0;i--){
            ll p = sum*1e9+ans[i];
            sum = p%MOD;
        }
        printf("Case #%d: %lld\n",cas++,sum);
    }
    return 0;
}


K:错排。基础题

 

M:玩井字棋。因为玩家是两步之内判断结果那么我们就考虑一步能不能胜利或一步后能不能有大等两个位置能使我们胜利就行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值