1011 Fliping game
一道简单的博弈,题目给了我们一个n*m的方阵,要求每次选择一个正面向上的硬币然后将从这个硬币到(n,m)之间的所有硬币翻面。谁最后找不到能翻的硬币谁就输。
因为无论怎么翻都要翻最后一个,所以当最后一个是正面的时候你就获得了必胜的能力,因为无论你怎么翻你都有最后那个硬币可以翻,因此一个简单判断就可以了。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <queue> #include <map> using namespace std; int s[105][105]; int n,m; int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { scanf("%d",&s[i][j]); } } if(s[n-1][m-1] == 0) printf("Bob\n"); else printf("Alice\n"); } return 0; }
1008 Hehe
一道简单的DP记录hehe的数量然后进行dp运算就行了。
因为互相之间差值是斐波那契数列开了一个数组存差指,表示效果不错^_^
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <queue> #include <map> using namespace std; #define maxn 2005 #define MOD 10007 #define INF 0xfffffff char s[12000]; int f[6000]; void get() { f[1]=1; f[2]=2; for(int i=3; i<=6000; i++) f[i]=(f[i-1]+f[i-2])%MOD; } int main() { get(); int t,counter = 1; scanf("%d",&t); getchar(); while(t--) { scanf("%s",s); int l=strlen(s); int ans=1; int al=0; for(int i=0; i<=l-4; i++) { if(s[i] == 'h' && s[i+1] == 'e') { int j = i+2; int sum = 1; while(s[j] == 'h'&&s[j+1] == 'e') { sum++; j+=2; } if(sum >= 2) { al++; ans = (f[sum] * ans)%MOD; } i = j-1; } } printf("Case %d: %d\n",counter++,ans); } return 0; }
1001 Palindrome subsequence
比赛时当时看完就感觉是区间DP,立马一通写,可是在去重的时候却出现了问题,老是想着加法的方式结果每次去重都是大幅的消耗时间,最后各种TLE,看了其他大牛的结题报告之后才发现原来可以直接减来去重,当时就囧了。。
还是思路不够广啊T_T
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <queue> #include <map> char s[1005]; int l; int dp[1005][1005]; int main() { int t,counter = 0; scanf("%d",&t); getchar(); while(t--) { counter++; gets(s); l = strlen(s); memset(dp,0,sizeof(dp)); for(int i = 0; i < l; i ++) { dp[i][i] = 1; } for(int i = 2; i <= l; i ++) { for(int j = 0; j + i - 1 < l; j ++) { int a = j; int b = j + i - 1; if(s[a] == s[b]) { dp[a][b] ++; } else { if(a + 1 <= b - 1) { dp[a][b] -= dp[a+1][b-1]; } } dp[a][b] += dp[a + 1][b] + dp[a][b-1]; dp[a][b] %= 10007; } } printf("Case %d: %d\n",counter,(dp[0][l-1]+10007)%10007); } return 0; }
1004Strongly connected
题目以强连通为名,自然做法也与强连通相关,可怜我还兴致勃勃的推规律,真想挖个坑把自己埋了T_T
不过嘛,规律的式子还是对的,就是对象偏了,即假定现在是n个点m条边,我们求出最小强连通分量为h(要求是出入度不全为0的强连通图)
我们可以求出最后的答案ans = n * (n - 1) - h * (n - h) - m
最初没想到出入度的问题,纠结了好久,后来写好后也是各种判断,时间效率很差,但是至少能过了感觉很开心^_^
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <queue> #include <map> using namespace std; #define maxn 1000005 struct node { int u,v,next; } edge[1000005]; int head[1000005]; int pos; int n,m; int num[maxn]; bool in[maxn]; bool out[maxn]; inline void RD(int &ret) { char c; do { c = getchar(); } while(c < '0' || c > '9') ; ret = c - '0'; while((c=getchar()) >= '0' && c <= '9') ret = ret * 10 + ( c - '0' ); } void insert() //创建有向图 { int x,y; for(int i=0; i<m; i++) { RD(x); RD(y); edge[pos].u = x; edge[pos].v = y; edge[pos].next = head[x]; head[x] = pos; pos++; } } int dfsn[maxn]; bool used[maxn]; int low[maxn]; int stack[maxn]; int scc[maxn]; int front; int number; int pre; bool Instack[maxn]; void dfs(int now) //DFS缩点形成多个小的强连通图 { front++; stack[front] = now; used[now] = 1; dfsn[now] = low[now] = pre; pre++; Instack[now] = 1; for(int i = head[now]; i; i = edge[i].next) //搜到为0,即已经不存在前置节点结束 { int v = edge[i].v; if(used[v] == 1) //所搜点已被使用的话则表示该点对应强连通图已被访问 { if(Instack[v] == 1) //表示是此强连通图的记录点 low[now] = min(low[now],dfsn[v]); continue; } dfs(v); //未找到对应位置需要继续DFS查找 low[now] = min(low[now],low[v]); } if(low[now] == dfsn[now])//找到的强连通存在重叠需要特判,确定强连通的大小 { number++; int mark; do { mark=stack[front--]; scc[mark]=number; Instack[mark]=false; } while(mark!=now); } } void init()//输入内容初始化 { memset(dfsn,0,sizeof(dfsn)); memset(low,0,sizeof(low)); memset(used,0,sizeof(used)); memset(Instack,0,sizeof(Instack)); pre=1; number=0; memset(head,0,sizeof(head)); pos=1; } void init2()//确定能分出两个全连通图后对出度入度初始化 { memset(num,0,sizeof(num)); for(int i=1; i<=n; i++) num[scc[i]]++; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); } int main() { int t,counter = 1; RD(t); while(t--) { RD(n); RD(m); init(); insert(); for(int i=1; i<=n; i++) { if(used[i] == 0) { front = -1; dfs(i); } } if(number == 1)//判断是否整体成强连通 { printf("Case %d: -1\n",counter++); continue; }//没有整体强连通则存在解,开始求最小强连通大小 init2(); for(int i=1; i<pos; i++) //pos为目前已有的强连通的数量,对所有的强连通图进行计算 { int x=edge[i].u; int y=edge[i].v; x=scc[x]; y=scc[y]; if(x != y)//不相等时存在出入度,变为1 { in[y]=1; out[x]=1; } } int h = maxn; for(int i=1; i<=number; i++) if(in[i] == 0||out[i] == 0)//判断出入度确定是否可用 h=min(h,num[i]); int ans = n * (n - 1) - h * (n - h) - m;//根据找出的最小强连通计算答案 printf("Case %d: %d\n",counter++,ans); } return 0; }
1007Group
题目要我们求在特定区域内存在的互相之间数字相邻的朋友的组数。
因为是10^5的数据,10^5的询问,在线写法几乎必爆,所以要改成用线段树或者树状数组进行离线处理,修改后就是简单的改改中间判断
很容易就能写出来了
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <queue> #include <map> using namespace std; #define maxn 100005 int n,m; int s[maxn]; int a[maxn]; int ss1[maxn]; int ans[maxn]; int lowbit(int x) { return x&(-x); } void add(int i,int val) { while(i <= n) { s[i] += val; i += lowbit(i); } } int sum(int i) { int sum = 0; while(i > 0) { sum += s[i]; i -= lowbit(i); } return sum; } struct node { int l,r; int index; }tt[maxn]; bool cmp(node x,node y) { return x.l < y.l; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(s,0,sizeof(s)); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); ss1[a[i]]=i; } ss1[0] = maxn; ss1[n+1] = maxn; for(int i = 1;i <= n;i++) { if(i < ss1[a[i]-1] && i < ss1[a[i]+1]) add(i,1); else if(i > ss1[a[i]-1] && i > ss1[a[i]+1]) add(i,-1); } for(int i = 0;i < m;i++) { scanf("%d%d",&tt[i].l,&tt[i].r); tt[i].index = i; } sort(tt,tt+m,cmp); int i = 1; int j = 0; while(j < m) { while(i <= n && i < tt[j].l) { if(i > ss1[a[i]-1] && i > ss1[a[i]+1]) add(i,-1); else if(i < ss1[a[i]-1] && i < ss1[a[i]+1]) { int Min = min(ss1[a[i]-1],ss1[a[i]+1]); int Max = max(ss1[a[i]-1],ss1[a[i]+1]); add(i,-1); add(Min,1); add(Max,1); } else if(i < ss1[a[i]-1]) { add(i,-1); add(ss1[a[i]-1],1); } else { add(i,-1); add(ss1[a[i]+1],1); } i++; } while( j < m && tt[j].l <= i) { ans[tt[j].index]= sum(tt[j].r); j++; } } for(int i = 0;i < m;i++) printf("%d\n",ans[i]); } return 0; }
1003Swipe Bo
冰面行走找出口的大模拟,情况略多,需要慢慢处理,整理好了再发上来^_^