B. Bounty Hunter II
求有向图中的最小路径覆盖。最小路径覆盖等于顶点数减去最大匹配数,直接用匈牙利算法即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define eps 1e-8
#define maxn 2050
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,m,k,ans;
int flag[maxn],linker[maxn];
vector<int>q[maxn];
bool dfs(int x)
{
for(int i=q[x].size()-1;i>=0;i--)
{
int u=q[x][i];
if(!flag[u])
{
flag[u]=1;
if(linker[u]==-1||dfs(linker[u]))
{
linker[u]=x;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
q[i].clear();
for(int i=0;i<n;i++)
{
scanf("%d",&m);
for(int j=0;j<m;j++)
{
scanf("%d",&k);
q[i].push_back(k+n);
}
}
ans=0;
memset(linker,-1,sizeof(linker));
for(int i=0;i<n;i++)
{
memset(flag,0,sizeof(flag));
if(dfs(i))ans++;
}
printf("%d\n",n-ans);
return 0;
}
E. Change of Scenery
无向图中判断1-n的最短路是否只有一条。
只需要维护一个num[i]表示从1到i最短路的数目,然后在dijkstra之后看num[n]是否大于1。
#include<cstdio>
#include<stack>
#include<map>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 10050
#define maxm 2000050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
int n,m,k,no,x,y;
int head[maxn],num[maxn];
bool flag[maxn];
ll dis[maxn],z,a;
struct node
{
int from;
int to;
ll w;
int nxt;
}e[maxm];
void add(int x,int y,ll z)
{
e[no].from=x;
e[no].to=y;
e[no].w=z;
e[no].nxt=head[x];
head[x]=no++;
}
void dijkstra()
{
memset(flag,0,sizeof(flag));
for(int i=0;i<=n;i++)
dis[i]=1ll*INF;
memset(num,0,sizeof(flag));
dis[1]=0,num[1]=1;
for(int i=1;i<=n;i++)
{
int kk=-1;
ll minn=INF;
for(int i=1;i<=n;i++)
{
if(!flag[i]&&dis[i]<minn)
{
minn=dis[i];
kk=i;
}
}
flag[kk]=1;
for(int i=head[kk];i!=-1;i=e[i].nxt)
{
int v=e[i].to;
int u=e[i].from;
if(!flag[v])
{
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
num[v]=num[u];
}
else if(dis[v]==dis[u]+e[i].w)
num[v]++;
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)scanf("%lld",&a);
no=0;
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dijkstra();
if(num[n]>1)printf("yes\n");
else printf("no\n");
return 0;
}
F. Divisions
求一个数的因子数目。
一个结论:将一个数进行质因数分解,写成n=a1^e1*a1^e2*...*ak^ek的形式,那么因子数目就是(1+e1)*(1+e2)*...*(1+ek)。
由于这个数很大,质因数分解需要使用大数因数分解的Pollard_Rho算法。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define maxn 100050
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
ll n;
ll fac[maxn];
int num=0;
ll mul(ll a,ll b,ll mod)
{
if(!a) return 0;
return ((a&1)*b%mod + (mul(a>>1,b,mod)<<1)%mod)%mod;
}
ll quickPow(ll a,ll d,ll n)
{
ll ret = 1;
while(d){
if(d&1) ret = mul(ret,a,n);
d >>= 1;
a = mul(a,a,n);
}
return ret;
}
bool check(ll a,ll d,ll n)
{
if(n == a) return true;
while(~d&1) d >>= 1;
ll t = quickPow(a,d,n);
while(d < n-1 && t != 1 && t != n-1){
t = mul(t,t,n);
d <<= 1;
}
return (d&1)||t == n-1;
}
bool isP(ll n)
{
if(n == 2) return true;
if(n < 2 || 0 == (n&1)) return false;
static int p[10] = {2,3,5,7,11,61,24251};
for(int i = 0; i < 7; ++i)
if(!check(p[i],n-1,n)) return false;
return true;
}
ll gcd(ll a,ll b)
{
ll t;
while(b)
{
t=a;
a=b;
b=t%b;
}
if(a>=0)return a;
else return -a;
}
ll pollard_rho(ll x,ll c)
{
ll i=1,k=2;
srand(time(NULL));
ll x0=rand()%(x-1)+1;
ll y=x0;
while(1)
{
i++;
x0=(mul(x0,x0,x)+c)%x;
ll d=gcd(y-x0,x);
if(d!=1&&d!=x)return d;
if(y==x0)return x;
if(i==k)
{
y=x0;
k+=k;
}
}
}
void findfac(ll n,int k)
{
if(n==1)return;
if(isP(n))
{
fac[num++]=n;
return;
}
ll p=n;
int c=k;
while(p>=n)
p=pollard_rho(p,c--);
findfac(p,k);
findfac(n/p,k);
}
int main()
{
scanf("%lld",&n);
findfac(n,107);
ll ans=1;
for(int i=0;i<num;i++)
{
int cnt=0;
while(n%fac[i]==0)
n/=fac[i],cnt++;
ans*=(cnt+1);
}
printf("%lld\n",ans);
return 0;
}
G. Extreme Sort
给一个数列,判断是不是按升序排过序的。
I. Milling Machines
直接模拟,在每个位置上取工件的最大长度,然后把捅完后剩下的长度和模具的长度比较即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define maxn 10050
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
int w,s,x,y,u;
int numw[maxn][105];
int nums[maxn];
int main()
{
scanf("%d%d",&w,&s);
scanf("%d%d",&x,&y);
for(int i=0;i<w;i++)
{
for(int j=0;j<x;j++)
scanf("%d",&numw[i][j]);
}
memset(nums,-1,sizeof(nums));
for(int i=0;i<s;i++)
{
for(int j=0;j<x;j++)
{
scanf("%d",&u);
nums[j]=max(nums[j],u);
}
}
for(int i=0;i<w;i++)
{
for(int j=0;j<x;j++)
{
printf("%d",min(numw[i][j],y-nums[j]));
if(j<x-1)printf(" ");
else printf("\n");
}
}
return 0;
}
K. Upside Down Primes
将一个七段译码器显示出来的数翻转,判断翻转前后是否都为素数。
除掉不合法的状况以后,就用Miller_Rabin算法判断是否为素数。
#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define maxn 19
#define INF 0x3f3f3f3f
#define mod 1e9+7
#define eps 1e-8
typedef long long ll;
using namespace std;
char s[maxn];
int n;
ll mul(ll a,ll b,ll mod) {
if(!a) return 0;
return ((a&1)*b%mod + (mul(a>>1,b,mod)<<1)%mod)%mod;
}
ll quickPow(ll a,ll d,ll n){
ll ret = 1;
while(d){
if(d&1) ret = mul(ret,a,n);
d >>= 1;
a = mul(a,a,n);
}
return ret;
}
bool check(ll a,ll d,ll n){
if(n == a) return true;
while(~d&1) d >>= 1;
ll t = quickPow(a,d,n);
while(d < n-1 && t != 1 && t != n-1){
t = mul(t,t,n);
d <<= 1;
}
return (d&1)||t == n-1;
}
bool isP(ll n){
if(n == 2) return true;
if(n < 2 || 0 == (n&1)) return false;
static int p[10] = {2,3,5,7,11,61,24251};
for(int i = 0; i < 7; ++i)
if(!check(p[i],n-1,n)) return false;
return true;
}
int main()
{
scanf("%s",s);
n=strlen(s);
ll ans=0,t=1;
for(int i=0;i<n;i++)
{
if(s[i]=='3'||s[i]=='4'||s[i]=='7')
{
printf("no\n");
return 0;
}
else if(s[i]=='6')ans+=(t*9);
else if(s[i]=='9')ans+=(t*6);
else if(s[i]=='0'||s[i]=='1'||s[i]=='2'||s[i]=='5'||s[i]=='8')
ans+=(t*(s[i]-'0'));
t*=10;
}
ll qnm=0;
ll cnm=1;
for(int i=n-1;i>=0;i--)
{
qnm+=((s[i]-'0')*cnm);
cnm*=10;
}
if(isP(ans)&&isP(qnm))
printf("yes\n");
else
printf("no\n");
return 0;
}