zoukankan      html  css  js  c++  java
  • 2017 ACM Jordanian Collegiate Programming Contest

    A. Chrome Tabs

    当$n=1$时答案为$0$,当$k=1$或$k=n$时答案为$1$,否则答案为$2$。

    #include<cstdio>
    int T,n,k;
    int main(){
    	freopen("tabs.in","r",stdin);
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d",&n,&k);
    		if(n==1)puts("0");
    		else if(k==1||k==n)puts("1");
    		else puts("2");
    	}
    }
    

      

    B. OverCode

    按题意模拟即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    int a[505];
    int main()
    {
    	freopen("overcode.in","r",stdin);
    	scanf("%d", &casenum);
    	for (casei = 1; casei <= casenum; ++casei)
    	{
    		scanf("%d", &n);
    		for(int i = 1; i <= n; ++i)scanf("%d", &a[i]);
    		sort(a + 1, a + n + 1);
    		int p = 1;
    		int ans = 0;
    		while(p <= n - 5)
    		{
    			if(a[p + 5] - a[p] <= 1000)
    			{
    				++ans;
    				p += 6;
    			}
    			else p += 1;
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    C. A message for you!

    按题意模拟即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    char s[20];
    int a[20];
    bool e[20];
    int main()
    {
    	freopen("scoreboard.in","r",stdin);
    	scanf("%d", &casenum);
    	for (casei = 1; casei <= casenum; ++casei)
    	{
    		scanf("%d", &n);
    		scanf("%s", s);
    		MS(e, 0);
    		for(int i = 0; i < n; i ++){
    			e[s[i] - 'A' + 1] = 1;
    		}
    		for(int i = 1; i <= 13; ++i)scanf("%d", &a[i]);
    		int ans = 0, tmp = 0;
    		for(int i = 1; i <= 13; i ++){
    			if(e[i] == 0 && a[i] > tmp){
    				tmp = a[i];
    				ans = i;
    			}
    		}
    		printf("%c
    ", ans + 'A' - 1);
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    D. Test Cases

    枚举左端点,往右枚举右端点,同时维护每个数字出现次数的奇偶性。

    时间复杂度$O(n^2)$。

    #include<cstdio>
    int T,n,i,j,odd,ans,v[1000010],a[5555];
    int main(){
    	freopen("cases.in","r",stdin);
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d",&n);
    		for(i=1;i<=n;i++)scanf("%d",&a[i]);
    		ans=0;
    		for(i=1;i<=n;i++){
    			for(j=i;j<=n;j++)v[a[j]]=0;
    			odd=0;
    			for(j=i;j<=n;j++){
    				v[a[j]]?odd--:odd++;
    				v[a[j]]^=1;
    				if(odd==1)ans++;
    			}
    		}
    		printf("%d
    ",ans);
    	}
    }
    

      

    E. Robot I - Instruction Reduction

    按题意模拟即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 505, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n, m, q;
    int y, x; char dir;
    char s[N][N];
    int f[N][N][4]; //real way
    const int dy[4] = {-1,0,1,0};
    const int dx[4] = {0,1,0,-1};
    int a[1010 * 1010];
    int Y, X, D;
    pair<int,int> ord[1010];
    int main()
    {
    	freopen("reduce.in","r",stdin);
    	scanf("%d", &casenum);
    	for (casei = 1; casei <= casenum; ++casei)
    	{
    		char dir;
    		scanf("%d%d%d", &n, &m, &q);
    		scanf("%d%d %c", &Y, &X, &dir);
    		if(dir == 'U')D = 0;
    		else if(dir == 'R')D = 1;
    		else if(dir == 'D')D = 2;
    		else D = 3;
    		int sty = Y, stx = X, stdir = D;
    		for(int i = 1; i <= n; ++i)
    		{
    			scanf("%s", s[i] + 1);
    		}
    		for(int i = 2; i < n; ++i)
    		{
    			for(int j = 2; j < m; ++j)if(s[i][j] == '.')
    			{
    				for(int d = 0; d < 4; ++d)
    				{
    					for(int k = 0; k < 4; ++k)
    					{
    						int dd = (d + k) % 4;
    						if(s[i + dy[dd]][j + dx[dd]] == '.')
    						{
    							f[i][j][d] = dd;
    							break;
    						}
    					}
    				}
    			}
    		}
    		//printf("f:%d
    ", f[3][2][1]);
    		int g = 0;
    		for(int i = 1; i <= q; ++i)
    		{
    			char op; scanf(" %c", &op);
    			if(op == 'R')
    			{
    				D = (D + 1) % 4;
    			}
    			else
    			{
    				int step;
    				scanf("%d", &step);
    				while(step--)
    				{
    					D = f[Y][X][D];
    					Y += dy[D];
    					X += dx[D];
    					a[++g] = D;
    				}
    			}
    		}
    		Y = sty, X = stx, D = stdir;
    		
    		//Y X D
    		int o = 0;
    		for(int i = 1; i <= g; ++i)
    		{
    			/*
    			printf("step = %d, status = %d %d %d, aimdir = %d
    ", i, Y, X, D, a[i]);
    			printf("f[%d][%d][%d] = %d, a[i] = %d
    ", Y, X, D, f[Y][X][D], a[i]);
    			getchar();
    			*/
    			for(int k = 0; k < 4; ++k)
    			{
    				if(f[Y][X][D] == a[i])
    				{
    					D = a[i];
    					Y += dy[D]; X += dx[D];
    					if(o && ord[o].first == 1)
    					{
    						++ord[o].second;
    					}
    					else ord[++o] = {1, 1};
    					break;
    				}
    				else
    				{
    					ord[++o] = {2, -99999999};
    					D = (D + 1) % 4;
    				}
    			}
    		}
    		printf("%d
    ", o);
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    F. Robot II - Colorful Grid

    留坑。

    G. WiFi Password

    枚举区间$OR$本质不同的$O(nlog w)$段区间,更新答案即可。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=100010;
    int T,n,lim,i,j,v[N],a[N],l[N],ans;
    inline int fun(int a,int b){return a|b;}
    int main(){
    	freopen("wifi.in","r",stdin);
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d",&n,&lim);
    		ans=0;
    		for(i=1;i<=n;i++)scanf("%d",&a[i]);
    		for(i=1;i<=n;i++)for(v[i]=a[i],j=l[i]=i;j;j=l[j]-1){
    			v[j]=fun(v[j],a[i]);
    			while(l[j]>1&&fun(a[i],v[l[j]-1])==fun(a[i],v[j]))l[j]=l[l[j]-1];
    			if(v[j]<=lim)ans=max(ans,i-l[j]+1);
    		}
    		printf("%d
    ",ans);
    	}
    }
    

      

    H. Gas Stations

    枚举去掉哪一个加油站,那么最优策略要么是在一开始插入,要么是在末尾插入,要么是将间隔最大的空段劈成两半,维护前$4$大即可快速询问。

    时间复杂度$O(n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=100010;
    int bestside[N];
    int T,n,m,ans,i,j,q[N];
    int pre[N],nxt[N];
    char a[N];
    int w[N],cnt;
    int now[N],tmp;
    inline bool cmp(int x,int y){return x>y;}
    inline int cal(int l,int r){
    	int dis=r-l-1;
    	if(l==0||r==n+1)return dis;
    	return (dis+1)/2;
    }
    inline int calleft(int mark){
    	for(int i=2;i<=m;i++)if(mark!=q[i])return q[i]-1;
    }
    inline int calright(int mark){
    	for(int i=m-1;i;i--)if(mark!=q[i])return n-q[i];
    }
    inline void gao(int l,int r){
    	if(l==0||r==n+1)return;
    	w[++cnt]=r-l-1;
    }
    inline void del(int l,int r){
    	if(l==0||r==n+1)return;
    	int dis=r-l-1;
    	int i;
    	for(i=1;i<=tmp;i++)if(now[i]==dis)break;
    	if(i>tmp)return;
    	for(;i<tmp;i++)now[i]=now[i+1];
    	tmp--;
    }
    inline void add(int l,int r){
    	if(l==0||r==n+1)return;
    	int dis=r-l-1;
    	int i;
    	now[++tmp]=dis;
    	sort(now+1,now+tmp+1,cmp);
    	if(tmp>4)tmp--;
    }
    inline void work(int x){
    	int i=pre[x],j=nxt[x];//i x j
    	tmp=cnt;
    	for(int _=1;_<=cnt;_++)now[_]=w[_];
    	del(i,x);
    	del(x,j);
    	add(i,j);
    	int left=calleft(x),right=calright(x);
    	int maxgap=0,secgap=0;
    	if(tmp>=1)maxgap=now[1];
    	if(tmp>=2)secgap=now[2];
    	//case 1 add one in left
    	ans=min(ans,max(bestside[left],max(right,(maxgap+1)/2)));
    	//case 2 add one in right
    	ans=min(ans,max(left,max(bestside[right],(maxgap+1)/2)));
    	//case 3 add one in maxgap
    	ans=min(ans,max(max(left,right),max((maxgap/2+1)/2,(secgap+1)/2)));
    }
    int main(){
    	freopen("stations.in","r",stdin);
    	
    	for(i=j=1;i<N;i++){
    		while(j<i&&max(j-1,(i-j+1)/2)>max(j,(i-(j+1)+1)/2))j++;
    		bestside[i]=max(j-1,(i-j+1)/2);
    		//i=3 |___+
    	}
    	
    	
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%s",&n,a+1);
    		ans=n;
    		q[m=1]=0;
    		for(i=1;i<=n;i++)if(a[i]=='+')q[++m]=i;
    		q[++m]=n+1;
    		
    		if(m==3){
    			for(i=1;i<=n;i++)ans=min(ans,max(cal(0,i),cal(i,n+1)));
    			printf("%d
    ",ans);
    			continue;
    		}
    		
    		
    		pre[0]=0;
    		nxt[n+1]=0;
    		for(i=1;i<=m;i++){
    			if(i>1)pre[q[i]]=q[i-1];
    			if(i<m)nxt[q[i]]=q[i+1];
    		}
    		cnt=0;
    		for(i=1;i<m;i++)gao(q[i],q[i+1]);
    		sort(w+1,w+cnt+1,cmp);
    		cnt=min(cnt,4);
    		for(i=2;i<m;i++)work(q[i]);
    		printf("%d
    ",ans);
    	}
    }
    

      

    I. Counting Votes

    留坑。

    J. Efficiency Test

    将环倍长,设$f[i][j]$表示在$i$点按$j$步长往右会跳到哪里,可以得到一棵树的结构,在树上DFS,询问时二分即可。

    常数优化:将失败的父亲合并,同时剔除子树内不含询问的点。

    时间复杂度$O(nk+nlog n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=200010,M=55,E=N*M;
    int Case,n,m,nn,i,j,cnt,s[N];
    int goal[N],ans[N];
    int g[E],nxt[E],f[E],q[E],t;
    bool vip[E];
    char a[N];
    inline bool canjump(int x,int y){
    	if(x+y>nn)return 0;
    	if(a[x+y]=='#')return 0;
    	return s[x+y]-s[x-1]<=1;
    }
    inline void gao(int x){
    	//printf("gao %d
    ",x);
    	//for(int i=2;i<=t;i++)printf("%d %d
    ",q[i],w[i]);
    	//[2..t]
    	int y=goal[x];
    	if(q[2]<y){ans[x]=-1;return;}
    	int l=3,r=t,mid,o=2;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(q[mid]>=y)l=(o=mid)+1;else r=mid-1;
    	}
    	ans[x]=f[t]-f[o];
    }
    void dfs(int x){
    	//printf("dfs %d
    ",x);
    	if(!vip[x])return;
    	int A=x/(m+1);
    	q[++t]=A;
    	f[t]=f[t-1];
    	if(q[t-1]!=A)f[t]++;
    	if(A&&A<=n&&x%(m+1)==m)gao(A);
    	for(int i=g[x];i;i=nxt[i])dfs(i);
    	t--;
    }
    int main(){
    	freopen("jumps.in","r",stdin);
    	scanf("%d",&Case);
    	while(Case--){
    		scanf("%d%d%s",&n,&m,a+1);
    		//for(i=1;i<=n;i++)a[i]='.';
    		//a[1]='#';
    		nn=n*2;
    		for(i=1;i<=n;i++)a[i+n]=a[i];
    		for(i=1;i<=nn;i++)s[i]=s[i-1]+(a[i]=='#');
    		//[2..m] is valid
    		cnt=nn*(m+1)+m;
    		for(i=0;i<=cnt;i++)g[i]=vip[i]=0;
    		for(i=nn;i;i--)if(a[i]=='.'){
    			int y=0;
    			for(j=2;j<=m;j++){
    				int x=i*(m+1)+j;
    				if(canjump(i,j))y=(i+j)*(m+1)+j;
    				f[x]=y;
    				//printf("f[%d][%d]=%d
    ",i,j,y);
    				//nxt[x]=g[y];
    				//g[y]=x;
    			}
    			int x=i*(m+1)+m;
    			while(!vip[x]){
    				vip[x]=1;
    				x=f[x];
    			}
    		}
    		for(i=1;i<=nn;i++)if(a[i]=='.'){
    			for(j=2;j<=m;j++){
    				int x=i*(m+1)+j;
    				if(!vip[x])continue;
    				int y=f[x];
    				nxt[x]=g[y];
    				g[y]=x;
    			}
    		}
    		for(i=j=1;i<=n;i++){
    			while(s[j]-s[i-1]<s[n])j++;
    			goal[i]=j;//>=j
    			//printf("goal[%d]=%d
    ",i,j);
    		}
    		dfs(0);
    		for(i=1;i<=n;i++){
    			if(a[i]=='#')printf("0 ");
    			else printf("%d ",ans[i]);
    		}
    		puts("");
    	}
    }
    

      

    K. Running Threads

    考虑费用流建图:

    • $S$向每条记录连边,流量$[0,1]$,费用$0$,表示一组的开始。
    • 记录$i$向记录$j$连边,流量$[0,1]$,费用$0$,表示一组延续。
    • 记录向线程连边,流量$[0,1]$,费用$w$,表示一组的结束。
    • 每条线程向$T$连边,流量$[0,1]$,费用$0$,表示只接受最多一组记录。
    • 每条记录拆点,中间连边,流量$[1,1]$,费用$0$。

    那么两问分别对应这个有上下界的网络的最小/最大费用可行流。

    #include<cstdio>
    typedef long long ll;
    const int N=1000,M=1000000;
    const ll inf=1LL<<60;
    int Case,n,m,i,j,a[N],b[N];
    ll sum;
    int u[M],v[M],c[M],co[M],nxt[M],t,S,T,SS,TT,l,r,q[M];
    int g[N],f[N];
    bool vis[N];
    ll d[N];
    int in[N];
    int tmp;ll ans;
    inline void add(int x,int y,int l,int r,int zo){
    	r-=l;
    	in[x]-=l;
    	in[y]+=l;
    	if(!r)return;
    	u[++t]=x;v[t]=y;c[t]=r;co[t]=zo;nxt[t]=g[x];g[x]=t;
    	u[++t]=y;v[t]=x;c[t]=0;co[t]=-zo;nxt[t]=g[y];g[y]=t;
    }
    bool spfa(){
    	int x,i;
    	for(i=1;i<=TT;i++)d[i]=inf,vis[i]=0;
    	d[SS]=0;
    	vis[SS]=1;
    	l=r=M>>1;
    	q[l]=SS;
    	while(l<=r){
    		int x=q[l++];
    		if(x==TT)continue;
    		for(i=g[x];i;i=nxt[i])if(c[i]&&co[i]+d[x]<d[v[i]]){
    			d[v[i]]=co[i]+d[x];f[v[i]]=i;
    			if(!vis[v[i]]){
    				vis[v[i]]=1;
    				if(d[v[i]]<d[q[l]])q[--l]=v[i];else q[++r]=v[i];
    			}
    		}
    		vis[x]=0;
    	}
    	return d[TT]<inf;
    }
    int main(){
    	freopen("threads.in","r",stdin);
    	scanf("%d",&Case);
    	while(Case--){
    		scanf("%d%d",&n,&m);
    		sum=0;
    		for(i=1;i<=m;i++)scanf("%d",&a[i]),sum+=a[i];
    		for(i=1;i<=n;i++)scanf("%d",&b[i]);
    		
    		S=n*2+m+1;
    		T=S+1;
    		SS=T+1;
    		TT=SS+1;
    		for(t=i=1;i<=TT;i++)g[i]=in[i]=0;
    		add(T,S,0,N,0);
    		for(i=1;i<=n;i++){
    			add(i,i+n,1,1,0);
    			add(S,i,0,1,0);
    			for(j=1;j<=m;j++)if(b[i]<=a[j])add(i+n,j+n*2,0,1,-b[i]);
    			for(j=i+1;j<=n;j++)if(b[i]<b[j])add(i+n,j,0,1,0);
    		}
    		for(i=1;i<=m;i++)add(i+n*2,T,0,1,0);
    		for(i=1;i<=TT;i++){
    			if(in[i]>0)add(SS,i,0,in[i],0);
    			if(in[i]<0)add(i,TT,0,-in[i],0);
    		}
    		ans=0;
    		while(spfa()){
    			for(tmp=N,i=TT;i!=SS;i=u[f[i]])if(tmp>c[f[i]])tmp=c[f[i]];
    			for(ans+=d[i=TT]*tmp;i!=SS;i=u[f[i]])c[f[i]]-=tmp,c[f[i]^1]+=tmp;
    		}
    		ans*=-1;
    		printf("%lld ",sum-ans);
    		
    		S=n*2+m+1;
    		T=S+1;
    		SS=T+1;
    		TT=SS+1;
    		for(t=i=1;i<=TT;i++)g[i]=in[i]=0;
    		add(T,S,0,N,0);
    		for(i=1;i<=n;i++){
    			add(i,i+n,1,1,0);
    			add(S,i,0,1,0);
    			for(j=1;j<=m;j++)if(b[i]<=a[j])add(i+n,j+n*2,0,1,b[i]);
    			for(j=i+1;j<=n;j++)if(b[i]<b[j])add(i+n,j,0,1,0);
    		}
    		for(i=1;i<=m;i++)add(i+n*2,T,0,1,0);
    		for(i=1;i<=TT;i++){
    			if(in[i]>0)add(SS,i,0,in[i],0);
    			if(in[i]<0)add(i,TT,0,-in[i],0);
    		}
    		ans=0;
    		while(spfa()){
    			for(tmp=N,i=TT;i!=SS;i=u[f[i]])if(tmp>c[f[i]])tmp=c[f[i]];
    			for(ans+=d[i=TT]*tmp;i!=SS;i=u[f[i]])c[f[i]]-=tmp,c[f[i]^1]+=tmp;
    		}
    		printf("%lld
    ",sum-ans);
    	}
    }
    /*
    3
    6 3
    8 12 7
    5
    3
    7
    3
    4
    9
    3 3
    1000000000 999999999 999999998
    1
    10
    1000
    5 3
    9 5 8
    9
    3
    6
    5
    8
    
    
    */
    

      

    L. Knights

    设$f[i][a][b][c][d]$表示从上到下考虑前$i$行,最后$4$行的骑士跳跃方向分别为$a,b,c,d$的方案数。

    需要根据可行性将$a$压缩到$3$,$b,c$压缩到$5$,$d$压缩到$7$才能通过。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=550,P=1000000007;
    int cnt,id[3][5][5][7],p[N][4],g[N][9];
    int Case,n,m,w,i,j,k,a[N],f[N][N],ans;
    char ch[N];
    int v[N][N];
    int dx[9]={0,2,2,1,1,-1,-1,-2,-2};
    int dy[9]={0,-1,1,-2,2,-2,2,-1,1};
    inline void up(int&a,int b){
    	a=a+b<P?a+b:a+b-P;
    }
    void init(){
    	for(int A=0;A<3;A++)for(int B=0;B<5;B++)for(int C=0;C<5;C++)for(int D=0;D<7;D++){
    		int now=cnt++;
    		id[A][B][C][D]=now;
    		p[now][0]=A;
    		p[now][1]=B;
    		p[now][2]=C;
    		p[now][3]=D;
    	}
    	for(int A=0;A<3;A++)for(int B=0;B<5;B++)for(int C=0;C<5;C++)for(int D=0;D<7;D++){
    		int now=id[A][B][C][D];
    		for(int i=1;i<9;i++){
    			int nA=B,nB=C,nC=D,nD=i;
    			if(nA>=3)nA=0;
    			if(nB>=5)nB=0;
    			if(nC>=5)nC=0;
    			if(nD>=7)nD=0;
    			g[now][i]=id[nA][nB][nC][nD];
    		}
    	}
    }
    int main(){
    	freopen("knights.in","r",stdin);
    	init();
    	scanf("%d",&Case);
    	while(Case--){
    		scanf("%d%d",&n,&m);
    		for(i=1;i<=n;i++){
    			scanf("%s",ch+1);
    			for(j=1;j<=m;j++){
    				if(ch[j]=='*')a[i]=j;
    				v[i][j]=ch[j]!='.';
    			}
    		}
    		for(i=0;i<=n;i++)for(j=0;j<cnt;j++)f[i][j]=0;
    		f[0][0]=1;
    		for(i=0;i<n;i++)for(j=0;j<cnt;j++)if(f[i][j]){
    			w=f[i][j];
    			int A=p[j][0],B=p[j][1],C=p[j][2],D=p[j][3];
    			if(A)v[i-3+dx[A]][a[i-3]+dy[A]]++;
    			if(B)v[i-2+dx[B]][a[i-2]+dy[B]]++;
    			if(C)v[i-1+dx[C]][a[i-1]+dy[C]]++;
    			if(D)v[i+dx[D]][a[i]+dy[D]]++;
    			for(k=1;k<9;k++){
    				int x=i+1+dx[k],y=a[i+1]+dy[k];
    				if(x>=1&&x<=n&&y>=1&&y<=m&&!v[x][y])
    					up(f[i+1][g[j][k]],w);
    			}
    			if(A)v[i-3+dx[A]][a[i-3]+dy[A]]--;
    			if(B)v[i-2+dx[B]][a[i-2]+dy[B]]--;
    			if(C)v[i-1+dx[C]][a[i-1]+dy[C]]--;
    			if(D)v[i+dx[D]][a[i]+dy[D]]--;
    		}
    		ans=0;
    		for(j=0;j<cnt;j++)up(ans,f[n][j]);
    		printf("%d
    ",ans);
    	}
    }
    

      

    M. Winning Cells

    问题等价于两个$K-Nim$游戏,那么只要$Amod (K+1) eq Bmod (K+1)$则先手必胜。

    反过来考虑计算必败态的个数,那么考虑$1$到$N$每个数模$K+1$的值,可以将这些数分成贡献不同的两组分别计算。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=100010;
    int T,n,k;long long ans;
    inline int fun(int a,int b){return a|b;}
    int main(){
    	freopen("chess.in","r",stdin);
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d",&n,&k);k++;
    		int m=n/k*k;
    		int base=n/k;
    		//[0..k-1] base
    		//[1..n%k] base+1
    		ans=1LL*n*n;
    		int A=n%k,B=k-A;
    		ans-=1LL*base*base*B;
    		base++;
    		ans-=1LL*base*base*A;
    		printf("%lld
    ",ans);
    	}
    }
    

      

  • 相关阅读:
    Nero8刻录引导系统光盘镜像图文教程
    C#多线程与并行编程方面的电子书,中英文版本
    [转]C#通过委托更新UI(异步加载)
    [PHP] 6种负载均衡算法
    [GIt] 团队工作效率分析工具gitstats
    [Git] git代码统计
    [Git] 写文章 史上最全文献检索、阅读及管理攻略
    [Git] 谷歌的代码管理
    [JQuery] jQuery选择器ID、CLASS、标签获取对象值、属性、设置css样式
    [Mongo] 解决mongoose不支持条件操作符 $gt$gte:$lte$ne $in $all $not
  • 原文地址:https://www.cnblogs.com/clrs97/p/7850455.html
Copyright © 2011-2022 走看看