day1:
生活大爆炸:
裸裸模拟。我是打一个01(胜负)的表,我觉得一一if比较麻烦。
参考程序:
#include<cstdio>
#include<algorithm>
#define maxn 300
using namespace std;
int a[maxn],b[maxn];
int c[5][5]={
{0,0,1,1,0},
{1,0,0,1,0},
{0,1,0,0,1},
{0,0,1,0,1},
{1,1,0,0,0},
};
int main(){
freopen("rps.in","r",stdin);
freopen("rps.out","w",stdout);
int na,nb,n;
scanf("%d%d%d",&n,&na,&nb);
for (int i=0;i<na;i++)
scanf("%d",&a[i]);
for (int i=0;i<nb;i++)
scanf("%d",&b[i]);
int i=0,j=0;
int resa=0,resb=0;
for (int k=0;k<n;k++){
resa+=c[a[i]][b[j]];
resb+=c[b[j]][a[i]];
i=(i+1)%na;j=(j+1)%nb;
}
printf("%d %d",resa,resb);
return 0;
}
联合权值:
裸裸的模拟,这是一个假“图论”,(提示:距离为2表示与该点距离为1的点距离为1不包括该点的点。。。比较绕)
因此为了简化问题,我们可以设sum[i]表示直接与点i相连的点的权值之和,ans[i]表示直接与点i相连的点的权值的最大值,pos[i]表示直接与点i相连的权值最大的那个点,sec[i]表示次大值,根据题目这些都在longlong范围内,无需高精度。预处理O(m)
那么,令v为所有与u距离为1的点,所有与点u距离为2的点j的权值和为w[u]*(sum[v]-w[u]),
而,所有j的权值的最大值就需要讨论,如果pos[v]=u则为sec[v],反之就是ans[v].
计算时就可以取模,还是无需高精度,效率O(m)。(无需建图,直接枚举边)
参考程序:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 410000
#define LL long long
using namespace std;
int n;
int max1[maxn],max2[maxn];
int pos[maxn];
LL sum[maxn];
int u[maxn],v[maxn],w[maxn];
int main(){
freopen("link.in","r",stdin);
freopen("link.out","w",stdout);
scanf("%d",&n);
for (int i=0;i<n-1;i++){
scanf("%d%d",&u[i],&v[i]);
u[n+i-1]=v[i];v[n+i-1]=u[i];
}
for (int i=1;i<=n;i++)
scanf("%d",&w[i]);
memset(max1,0,sizeof(max1));
memset(max2,0,sizeof(max2));
memset(sum,0,sizeof(sum));
for (int i=0;i<2*n-2;i++){
if (w[v[i]]>max1[u[i]]){
max2[u[i]]=max1[u[i]];
max1[u[i]]=w[v[i]];
pos[u[i]]=v[i];
}else if (w[v[i]]>max2[u[i]]){
max2[u[i]]=w[v[i]];
}
sum[u[i]]+=w[v[i]];
}
LL ans=0;
int res=0;
for (int i=0;i<2*n-2;i++){
if(pos[v[i]]==u[i])
res=max(res,max2[v[i]]*w[u[i]]);
else res=max(res,max1[v[i]]*w[u[i]]);
ans+=(sum[v[i]]-w[u[i]])*w[u[i]];
ans%=10007;
}
printf("%d %lld",res,ans);
return 0;
}
飞扬的小鸟:
稍稍麻烦一点的裸无限背包。
参考程序:
#include<cstdio>
#include<algorithm>
#define INF 0x3f3f3f3f
#define maxn 11000
using namespace std;
int n,m,p;
int x[maxn],y[maxn];
int l[maxn],h[maxn];
int f[maxn][1100];
bool mark[maxn];
int main(){
freopen("bird.in","r",stdin);
freopen("bird.out","w",stdout);
scanf("%d%d%d",&n,&m,&p);
for (int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
memset(l,0,sizeof(l));
memset(h,0x3f,sizeof(h));
for (int i=1;i<=p;i++){
int no;
scanf("%d",&no);
scanf("%d%d",&l[no],&h[no]);
mark[no]=true;
}
memset(f,0x3f,sizeof(f));
for (int i=0;i<=m;i++)
f[0][i]=0;
//for (int i=1;i<=n;i++)
// printf("%d %d %d\n",mark[i],l[i],h[i]);
int res=0;
for (int i=1;i<=n;i++){
for (int j=x[i]+1;j<=m;j++)
f[i][j]=min(f[i][j],min(f[i-1][j-x[i]],f[i][j-x[i]])+1);
for (int j=m-x[i];j<=m;j++)
f[i][m]=min(f[i][m],min(f[i-1][j],f[i][j])+1);
for (int j=1;j<=m-y[i];j++)
f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
if (mark[i]){
for (int j=0;j<=l[i];j++)
f[i][j]=INF;
for (int j=h[i];j<=m;j++)
f[i][j]=INF;
}
bool flag=false;
for (int j=1;j<=m;j++)
if (f[i][j]!=INF)flag=true;
if (flag)res+=mark[i];
else{
printf("0\n%d\n",res);
return 0;
}
}
int ans=INF;
for (int i=1;i<=m;i++)
ans=min(ans,f[n][i]);
/*for (int j=0;j<=m;j++){
for (int i=0;i<=n;i++)
printf("%5d ",f[i][j]==INF?-1:f[i][j]);
printf("\n");
}*/
printf("1\n%d\n",ans);
return 0;
}
day2:
无线网:
两层循环模拟,设f[i][j]表示从[0,0]到[i,j]的矩阵中公共场所的总数,预处理O(n^2),然后枚举中心点,向左右扩展用f[i][j]O(1)的速度算出打擂台即可。
参考程序:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=500;
int a[maxn][maxn];
int f[maxn][maxn];
int d,n;
int main(){
freopen("wireless.in","r",stdin);
freopen("wireless.out","w",stdout);
scanf("%d%d",&d,&n);
for (int i=0;i<n;i++){
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
x++;y++;
a[x][y]=k;
}
for (int i=1;i<=129;i++)
for (int j=1;j<=129;j++)
f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]-f[i-1][j-1]+a[i][j]);
int cnt=0,ans=0;
for (int i=1;i<=129;i++)
for (int j=1;j<=129;j++){
int x1=max(i-d,1),x2=min(i+d,129),y1=max(j-d,1),y2=min(j+d,129);
int z=f[x2][y2]-f[x1-1][y2]-f[x2][y1-1]+f[x1-1][y1-1];
if (z>ans){
ans=z;cnt=1;
}else
if (z==ans)cnt++;
}
printf("%d %d",cnt,ans);
return 0;
}
寻找道路:
这是真的图,建两个图,一个是顺向,一个是反向,先用反向图dfs出能到t的点,再在顺向图中筛出符合条件一的点,最后spfa即可。
参考程序:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<ctime>
#define maxn 210000
using namespace std;
struct Node{
int j,next;
}e[maxn],E[maxn];
int a[maxn],A[maxn],dis[maxn];
int n,m,s,t,NodeCnt=0;
bool ok[maxn],can[maxn],inq[maxn],vis[maxn];
queue<int> Q;
void addedge(int u,int v){
int p=++NodeCnt;
e[p].j=v;e[p].next=a[u];
a[u]=p;
E[p].j=u;E[p].next=A[v];
A[v]=p;
}
void dfs(int x){
if (can[x])return;
can[x]=true;
for (int p=A[x];p;p=E[p].next){
int j=E[p].j;
dfs(j);
}
}
int spfa(int s){
memset(dis,0x3f,sizeof(dis));
memset(inq,0,sizeof(inq));
int INF=dis[0];
Q.push(s);
dis[s]=0;inq[s]=true;
while (!Q.empty()){
int u=Q.front();inq[u]=false;Q.pop();
for (int p=a[u];p;p=e[p].next){
int j=e[p].j;
if (ok[j] && dis[j]>dis[u]+1){
dis[j]=dis[u]+1;
if (!inq[j]){
Q.push(j);
inq[j]=true;
}
}
}
}
return dis[t]==INF?-1:dis[t];
}
int main(){
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=0;i<m;i++){
int u,v;
scanf("%d%d",&u,&v);
if (u==v)continue;
addedge(u,v);
}
scanf("%d%d",&s,&t);
dfs(t);
for (int i=1;i<=n;i++){
ok[i]=true;
for (int p=a[i];p;p=e[p].next){
int j=e[p].j;
ok[i]&=can[j];
}
}
printf("%d",spfa(s));
return 0;
}
解方程:
这一题比较坑,神犇一眼看出用秦九韶算法,可是,
我们就模质数吧,如果模了后的左式为0,可以粗略的认为这个就是根,多模几个质数即可,然后预处理出(1,p)(p指该质数)左式的值,可知f(x)=f(x+p)(mod p),根据一个根即可得出其他的根。
参考程序:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 11000
using namespace std;
int pri[5]={11261,19997,22877,21893,14843};
char Ai[maxn];
int a[5][maxn];
int pre[5][maxn];
int ans[100*maxn];
int res[5][3*maxn];
int n,m;
int cal(int k,int x){
int sum=0;
for (int i=0;i<=n;i++)
sum=(sum+a[k][i]*pre[k][i])%pri[k];
if (sum<0)sum+=pri[k];
return sum;
}
int check(int x){
for (int k=0;k<5;k++)
if (res[k][x%pri[k]])return false;
return true;
}
int main(){
freopen("equation.in","r",stdin);
freopen("equation.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=0;i<=n;i++){
scanf("%s",Ai);
int lt=strlen(Ai);
bool flag=0;
for (int k=0;k<5;k++)
if (Ai[0]!='-')a[k][i]=Ai[0]-'0';
else a[k][i]=0,flag=true;
for (int k=0;k<5;k++){
for (int j=1;j<lt;j++)
a[k][i]=(a[k][i]*10+Ai[j]-48)%pri[k];
if (flag)a[k][i]=-a[k][i];
}
}
for (int k=0;k<5;k++)
for (int x=1;x<pri[k];x++){
pre[k][0]=1;
for (int i=1;i<=n;i++)
pre[k][i]=(pre[k][i-1]*x)%pri[k];
res[k][x]=cal(k,x);
}
int cnt=0;
for (int i=1;i<=m;i++)
if (check(i))ans[++cnt]=i;
printf("%d\n",cnt);
for (int i=1;i<=cnt;i++)
printf("%d\n",ans[i]);
return 0;
}
给神犇解读的秦九韶:
var pr:array[0..70]of int64;
b:array[0..1000010]of boolean;
a:array[0..10010]of longint;
c:array[0..110,0..70]of int64;
fh:array[0..110]of longint;
ys:array[0..6000]of boolean;
n,m,i,j,k,s,ans,l:longint;
ok:boolean;
num,q:int64;
ch:char;
begin
assign(input,'equation.in');reset(input);
assign(output,'equation.out');rewrite(output);
readln(n,m);
s:=1;
pr[s]:=5683;
num:=int64(200000)*200000;
repeat
num:=num+1;ok:=true;
for i:=2 to 200000 do
if num mod i=0 then
begin
ok:=false;
break;
end;
if ok then begin s:=s+1;pr[s]:=num;end;
until s=10;
for i:=0 to n do
begin
repeat
read(ch);
until ch>' ';
if ch='-'then
begin
fh[i]:=-1;
read(ch);
end
else fh[i]:=1;
l:=1;
q:=1;
fillchar(a,sizeof(a),0);
repeat
if q=1000000 then
begin
l:=l+1;
q:=1;
end;
a[l]:=a[l]*10+ord(ch)-48;
q:=q*10;
if seekeoln(input)then break;
read(ch);
until false;
for j:=1 to s do
begin
num:=0;
for k:=1 to l-1 do num:=(num*1000000+a[k])mod pr[j];
num:=(num*q+a[l])mod int64(pr[j]);
c[i,j]:=num*fh[i];
end;
end;
for i:=1 to m do
begin
if(i>5683)and(ys[(i-1)mod 5683+1]=false)then continue;
b[i]:=true;
for j:=1 to s do
if b[i] then
begin
num:=0;
for k:=n downto 0 do num:=(num*i+c[k,j])mod pr[j];
if(i<=5683)and(j=1)then ys[i]:=(num=0);
if num<>0 then b[i]:=false;
end;
end;
for i:=1 to m do
if b[i] then ans:=ans+1;
writeln(ans);for i:=1 to m do if b[i]then writeln(i);
close(input);close(output);
end.