5小时内:
- A 水
- D KMP
- K 组合数求%和错排问题
- L 模拟题
之后:
- B 计算几何基础
A
没啥好写的,鸡兔同笼…
D
kmp,对了比赛时我没判断后面那个串后面有没有0也过了,但是应该是需要判断的。
L
题意:判断先手下两步,后手下一步,先手能不能赢。
思路:模拟,判断直接赢,下一步赢,和模拟A下一步,B下一步的所有的过程。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <sstream>
using namespace std;
int data[5][5];
bool check(int th)
{
for(int i = 0; i < 3; i++)
{
int num = 0;
for(int j = 0; j < 3; j++)
if(data[i][j] == th) num ++;
if(num == 3) return true;
}
for(int j = 0; j < 3; j++)
{
int num = 0;
for(int i = 0; i < 3; i++)
if(data[i][j] == th) num ++;
if(num == 3) return true;
}
int num = 0;
for(int i = 0; i < 3; i++)
if(data[i][i] == th) num++;
if(num == 3) return true;
num = 0;
for(int i = 2; i >= 0; i--)
if(data[i][2-i] == th) num++;
if(num == 3) return true;
return false;
}
bool meiyou(int th,int ta)
{
int flag = 0,tanum = 0;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
{
if(data[i][j] == 0)
{
tanum++;
data[i][j] = ta;
int num = 0,mark = 0;
for(int k = 0; k < 3; k++)
for(int m = 0; m < 3; m++)
{
if(data[k][m] == 0)
{
num++;
data[k][m] = th;
if(check(th)) mark = 1;
data[k][m] = 0;
}
}
data[i][j] = 0;
if(mark) continue;
if(!mark) flag = 1;
if(flag || num == 0) return 0;
}
}
if(tanum == 0) return 0;
return 1;
}
void solve(int th)
{
int ta = th == 1 ? 2:1;
if(check(th)) {printf("Kim win!\n");return;}
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
{
if(data[i][j] == 0)
{
data[i][j] = th;
int temp = check(th);
data[i][j] = 0;
if(temp) {printf("Kim win!\n");return;}
}
}
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
{
if(data[i][j] == 0)
{
data[i][j] = th;
if(meiyou(th,ta)){printf("Kim win!\n"); return;}
data[i][j] = 0;
}
}
printf("Cannot win!\n");
}
int main()
{
int t;
char str[50],temp[50];
scanf("%d",&t);
while(t--)
{
getchar();
memset(data,0,sizeof(data));
for(int i = 0; i < 3; i++)
{
cin.getline(str,50);
stringstream ss;
ss << str;
int num = 0;
while(ss >> temp)
{
int slen = strlen(temp);
for(int j = 0; j < slen; j++)
{
if(temp[j]=='o')data[i][num] = 1;
else if(temp[j] == 'x') data[i][num] = 2;
num++;
}
}
}
cin >> str;
if(str[0] == 'o') solve(1);
else solve(2);
}
return 0;
}
K
挑战程序设计竞赛上有板子,我数学题写的少,所以就直接掏了那个函数上来。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
const int maxn = 1e4 + 10;
const ll mod = 1e9+7;
ll D[maxn],fact[maxn];
void pre()
{
D[0] = 1 ; D[1] = 0, D[2] = 1;
for(int i = 3; i <= maxn; i++)
D[i] = (i-1)*(D[i-1] + D[i-2]) % mod;
fact[1] = 1,fact[0] = 1;
for(int i = 2; i <= maxn; i++)
fact[i] = (i*fact[i-1]) % mod;
}
ll extgcd(ll a,ll b,ll &x,ll &y)
{
ll d = a;
if(b != 0)
{
d = extgcd(b,a%b,y,x);
y -= (a/b)*x;
}
else{x = 1; y = 0;}
return d;
}
ll mod_inverse(ll a)
{
ll x,y;
extgcd(a,mod,x,y);
return (mod+x%mod)%mod;
}
ll mod_fact(ll n,ll &e)
{
e = 0;
if(n == 0) return 1;
ll res = mod_fact(n/mod,e);
e += n/mod;
if(n/mod%2) return res*(mod-fact[n%mod])%mod;
return res * fact[n%mod]%mod;
}
ll mod_comb(ll n,ll k)
{
if(n < 0 || k < 0 || n < k) return 0;
ll e1 ,e2, e3;
ll a1 = mod_fact(n,e1), a2 = mod_fact(k,e2), a3 = mod_fact(n-k,e3);
if(e1 > e2 + e3) return 0;
return a1*mod_inverse(a2*a3%mod)%mod;
}
int main()
{
int t;
pre();
scanf("%d",&t);
int n,k;
while(t--)
{
scanf("%d%d",&n,&k);
ll ans = 0;
for(int i = 0; i <= n-k; i++)
{
ll temp = mod_comb(n,i) * D[i] % mod;
ans = (ans + temp)%mod;
}
cout << ans << endl;
}
return 0;
}
/*错排公式
D(n) = (n-1) [D(n-2) + D(n-1)]
D(1) = 0, D(2) = 1.
*/
今天补:
B
计算几何,上板子吧。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct point
{
int x,y;
point(){}
point(int a,int b){x = a;y = b;}
bool operator== (point b)
{ return (x == b.x) && (y == b.y); }
point operator- (point b)
{ return point(x-b.x,y-b.y); }
};
int dcmp(int x)
{ if(x == 0) return 0; else return x < 0 ? -1:1; }
int Cross(point a , point b) {return a.x*b.y - a.y*b.x;} //叉乘
int Dot(point a , point b) {return a.x*b.x+a.y*b.y;} //点乘
point poi[6]; int data[12];
bool isPointOnSegment(point p,point a1,point a2) //点是否在线段上
{
return dcmp(Cross(a1-p,a2-p)) == 0 && dcmp(Dot(a1-p,a2-p)) < 0;
}
bool SegIntersect(point a1,point a2,point b1,point b2) //两条线是否相交(规范相交)
{
int c1 = Cross(a2-a1,b1-a1), c2 = Cross(a2-a1,b2-a1),
c3 = Cross(b2-b1,a1-b1), c4 = Cross(b2-b1,a2-b1);
if(c1 == c2&&c1 == 0) return 1;
else return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
int isPointInPolygon(int id,int way) //转角法判断点是否在多边形内部
{
int wn = 0;
for(int i = 0; i < 3; i++)
{
int ai = i+3, bi = i+4;
if(bi == 6) bi = 3;
if(way == 1) ai -= 3,bi -= 3;
point a = poi[ai],b = poi[bi];
if(isPointOnSegment(poi[id],a,b) || a == poi[id] || b == poi[id]) return -1; //在边上
int k = dcmp(Cross(b-a,poi[id]-a));
int d1 = dcmp(a.y - poi[id].y);
int d2 = dcmp(b.y - poi[id].y);
if(k > 0 && d1 <= 0 && d2 > 0) wn++;
if(k < 0 && d2 <= 0 && d1 > 0) wn--;
}
if(wn != 0) return 1;
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
for(int i = 0; i < 12; i++) scanf("%d",&data[i]);
for(int i = 0; i < 6; i++)
poi[i].x = data[2*i], poi[i].y = data[2*i+1];
int ans = 0,flag = 0,mark = 0;
for(int i = 0; i < 3; i++)
{
int a1 = i,a2 = i+1; if(a2 == 3) a2 -= 3;
for(int j = 3; j < 6; j++)
{
int b1 = j, b2 = j+1; if(b2 == 6) b2 -= 3;
if(SegIntersect(poi[a1],poi[a2],poi[b1],poi[b2])) ans = 1;
if(isPointOnSegment(poi[a1],poi[b1],poi[b2])
|| poi[a1] == poi[b1] || poi[a1] == poi[b2]) flag = 1;
if(isPointInPolygon(j,1)) mark = 1;
}
if(isPointInPolygon(i,0)) mark = 1;
}
if(flag || ans ) printf("intersect\n");
else
{
if(mark) printf("contain\n");
else printf("disjoint\n");
}
}
return 0;
}