A. Crazy Town

  這一題只需要考慮是否經過所給的線,如果起點和終點都在其中一條線的一側,那麼很明顯從起點走點終點是不需要穿過這條線的,否則則一定要經過這條線,並且步數+1。用叉積判斷即可。

程式碼:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#define N 100010
#define M 1010
using namespace std;
int x1,y1,x2,y2,a,b,c,i,ans,n;
double x,y,xx,yy;
double cross(double x1,double y1,double x2,double y2,double x3,double y3)
{
return (x2-x1)*(y3-y1)-(x3-x1)*(y2-y1);
}
int main()
{
scanf("%d%d",&x1,&y1);
scanf("%d%d",&x2,&y2);
scanf("%d",&n);
for (i=;i<=n;i++)
{
scanf("%d%d%d",&a,&b,&c);
if (b)
{
x=;
y=(-c-a)*1.0/b;
xx=;
yy=(-c-*a)*1.0/b;
}
else
{
y=;
x=(-c-b)*1.0/a;
yy=;
xx=(-c-*b)*1.0/a;
}
if (cross(x,y,xx,yy,x1,y1)*cross(x,y,xx,yy,x2,y2)<)
ans++;
}
printf("%d",ans);
}

C. Array and Operations

  要使運算元目最多首先每個操作肯定是要除以一個質數的,因為一個合數可以拆成多個質數,那麼運算元目明顯會增加。對於每個質數可以獨立考慮,對於一個質數x,假設a[i]中有sum[i]個x,一次操作會使一個數對同時減少一個x,現在要考慮的就是如何操作使得操作次數最多,由於題目保證數對的和是奇數,也就是一個數對分別有一個奇數和一個偶數,那麼就可以建二分圖跑網路流,對於一個數對,假設L[i]是奇數,R[i]是偶數,那麼從源點s連一條流量為sum[L[i]]的邊到L[i],L[i]連一條流量無窮大的邊到R[i],R[i]連一條流量為sum[R[i]]的邊到匯點t。跑出來的最大流就是對於質數x的最大運算元,對於每個質數的運算元累加起來就是答案。

程式碼

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#define N 100010
#define M 810
#define INF 0x37373737
using namespace std;
int dp,pre[M],p[M],tt[M],g[M],vis[M],dis[M],z[N],now[M],s,t,a[N],sum[N];
int n,m,i,L[N],R[N],flag,j,ans;
void link(int x,int y,int z)
{
dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;g[dp]=z;
dp++;pre[dp]=p[y];p[y]=dp;tt[dp]=x;g[dp]=;
}
int min(int a,int b)
{
if (a<b) return a;return b;
}
int bfs()
{
int i,head,tail;
memcpy(now,p,sizeof(p));
memset(vis,,sizeof(vis));
head=;tail=;
vis[s]=;
dis[s]=;
z[tail]=s;
do
{
head++;
i=p[z[head]];
while (i)
{
if ((vis[tt[i]]==)&&(g[i]>))
{
vis[tt[i]]=;
dis[tt[i]]=dis[z[head]]+;
tail++;z[tail]=tt[i];
}
i=pre[i];
}
}
while (head!=tail);
return vis[t];
}
int dfs(int u,int flow)
{
int ans,tmp,i;
if (u==t) return flow;
i=now[u];
ans=;
while (i)
{
if ((dis[u]+==dis[tt[i]])&&(g[i]>))
{
tmp=dfs(tt[i],min(flow-ans,g[i]));
ans+=tmp;g[i]-=tmp;
if (i%==) g[i+]+=tmp;else g[i-]+=tmp;
if (flow==ans) return flow;
}
i=pre[i];
now[u]=i;
}
if (flow>ans) dis[u]=;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (i=;i<=n;i++)
scanf("%d",&a[i]);
for (i=;i<=m;i++)
scanf("%d%d",&L[i],&R[i]);
for (i=;i<=;i++)
{
flag=;
for (j=;j<=n;j++)
if (a[j]%i==)
{
flag=;
while (a[j]%i==)
{
sum[j]++;a[j]=a[j]/i;
}
}
//----------------------------
if (flag)
{
dp=;
memset(p,,sizeof(p));
s=;t=n+;
for (j=;j<=n;j++)
if (j%==)
link(j,t,sum[j]);
else
link(s,j,sum[j]);
for (j=;j<=m;j++)
if (L[j]%==)
link(R[j],L[j],INF);
else
link(L[j],R[j],INF);
while (bfs()) ans=ans+dfs(s,INF);
for (j=;j<=n;j++)
sum[j]=;
}
flag=;
}
for (i=;i<=n;i++)
if (a[i]>)
{
flag=a[i];
for (j=;j<=n;j++)
while (a[j]%flag==)
{
sum[j]++;a[j]=a[j]/flag;
}
dp=;
memset(p,,sizeof(p));
s=;t=n+;
for (j=;j<=n;j++)
if (j%==)
link(j,t,sum[j]);
else
link(s,j,sum[j]);
for (j=;j<=m;j++)
if (L[j]%==)
link(R[j],L[j],INF);
else
link(L[j],R[j],INF);
while (bfs()) ans=ans+dfs(s,INF);
for (j=;j<=n;j++)
sum[j]=;
}
printf("%d",ans);
}

D. Traffic Jams in the Land

  正解是線段樹,由於a[i]的值只可能是2到6,假設當前到了節點i,用了時間time,那麼對於當前是要花費1s時間經過還是2s時間經過,用time和time%lcm(2,3,4,5,6)判斷是沒有差別的,那麼對於線段樹的每個節點都開60個數組,分別表示在(time&60)的時間進入該節點所表示的線段,並用了多少時間走出去,這樣就可以對線段樹進行修改和查詢了。下面貼出的程式碼是用分塊做的,塊內元素固定為40,思想是和線段樹一樣的,只是每次修改都對所在的塊暴力維護,也能卡過所有的資料。。。。

程式碼

 #include<cstdio>
#include<cstring>
#define N 100100
#define Q 40
int n,i,j,a[N],s[][],q,x,y,bx,by,tmp;
char ch;
int min(int a,int b)
{
if (a<b) return a;return b;
}
void change(int x)
{
int i,j,tmp;
for (j=;j<=;j++)
{
tmp=j;
for (i=(x-)*Q+;i<=min(x*Q,n);i++)
{
if (tmp%a[i]==) tmp++;
tmp++;
}
s[x][j]=tmp-j;
}
}
int query(int x,int y,int bx,int by)
{
int i,tmp;
tmp=;
for (i=x;i<=bx*Q;i++)
{
if (tmp%a[i]==) tmp++;
tmp++;
}
for (i=bx+;i<=by-;i++)
tmp=tmp+s[i][tmp%];
for (i=(by-)*Q+;i<=y;i++)
{
if (tmp%a[i]==) tmp++;
tmp++;
}
return tmp;
}
int main()
{
scanf("%d",&n);
for (i=;i<=n;i++)
scanf("%d",&a[i]);
for (i=;i<=(n-)/Q+;i++)
change(i);
scanf("%d",&q);
for (i=;i<=q;i++)
{
getchar();
scanf("%c%d%d",&ch,&x,&y);
if (ch=='C')
{
a[x]=y;
change((x-)/Q+);
}
else
{
y--;
bx=(x-)/Q+;
by=(y-)/Q+;
if (bx==by)
{
tmp=;
for (j=x;j<=y;j++)
{
if (tmp%a[j]==) tmp++;
tmp++;
}
printf("%d\n",tmp);
}
else
{
printf("%d\n",query(x,y,bx,by));
}
}
}
}